I'm trying to create a very simple transaction manager like this:
object PersistenceManager {
private val dataSource: DataSource by lazy {
val config = ConfigFactory.load()
hikari(config.getConfig("postgres"))
}
private fun hikari(appConfig: Config): DataSource {
// init datasource
}
fun <T> transaction(statement: Connection.() -> T): T {
val connection = dataSource.connection
try {
return connection.statement()
} catch (e: Exception) {
connection.rollback()
throw e
} finally {
connection?.close()
}
}
}
class BrandsDB {
private val query = "select name from brands order by name"
fun Connection.getAll(): List<String> {
val ps = this.prepareStatement(query)
val rs = ps.executeQuery()
return JdbcMapperFactory.newInstance()
.newMapper(String::class.java)!!.stream(rs).toList()
}
}
class BrandsService(private val brandsDB: BrandsDB) {
fun getBrands(): List<String> {
return transaction {
brandsDB.getAll() // I'd like to do something like this but since
// getAll() method belongs to Connecion, I can't
}
}
}
So the idea behind all this is that I can have multiple queries in a single transaction
block which I can rollback if anything goes wrong (should I have inserts or updates in those queries). I'd also like to avoid passing the connection to the brandsDB.getAll()
method, but have it get the connection in an "implicit" way.
I know I could extract getAll()
method to its own file or make BrandsDB
class an object, but that'd make it possible to call the method anywhere in a static way, which I don't like. I'd also wouldn't like to put any DB related code in the BrandsService
, only business logic should go there.
Would this be possible?