Skip to content

Instantly share code, notes, and snippets.

@sazid
Created August 30, 2021 06:59
Show Gist options
  • Save sazid/1578fea326c5b8cae09faf6d09435915 to your computer and use it in GitHub Desktop.
Save sazid/1578fea326c5b8cae09faf6d09435915 to your computer and use it in GitHub Desktop.
Database utilities for JDBC
package io.github.sazid
import java.sql.Connection
import java.sql.Date
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.time.LocalDate
import javax.sql.DataSource
typealias RowMapper<T> = (ResultSet) -> T
@Suppress("MemberVisibilityCanBePrivate")
object DBUtils {
fun execute(ds: DataSource, q: String, vararg binds: Any?): Boolean =
ds.connection.use { execute(it, q, *binds) }
fun execute(conn: Connection, q: String, vararg binds: Any?): Boolean =
conn.prepareStatement(q).use {
bindValues(it, *binds)
it.execute()
}
fun executeCount(ds: DataSource, q: String, vararg binds: Any?): Int =
ds.connection.use { executeCount(it, q, *binds) }
fun executeCount(conn: Connection, q: String, vararg binds: Any?): Int =
conn.prepareStatement(q).use { stmt ->
bindValues(stmt, *binds)
stmt.executeUpdate()
}
fun <R> query(ds: DataSource, q: String, mapper: RowMapper<R>, vararg binds: Any?): R =
ds.connection.use { query(it, q, mapper, *binds) }
fun <R> query(conn: Connection, q: String, mapper: RowMapper<R>, vararg binds: Any?): R =
conn.prepareStatement(q).use { stmt ->
bindValues(stmt, *binds)
stmt.executeQuery().use { mapper(it) }
}
fun <R> list(ds: DataSource, q: String, mapper: RowMapper<R>, vararg binds: Any?): List<R> =
ds.connection.use { list(it, q, mapper, *binds) }
fun <R> list(conn: Connection, q: String, mapper: RowMapper<R>, vararg binds: Any?): List<R> =
query(conn, q, {
it.use { rs ->
val result = mutableListOf<R>()
while (rs.next()) {
result += mapper(rs)
}
result
}
}, *binds)
fun <R> one(ds: DataSource, q: String, mapper: RowMapper<R>, vararg binds: Any?): R? =
ds.connection.use { one(it, q, mapper, *binds) }
fun <R> one(conn: Connection, q: String, mapper: RowMapper<R>, vararg binds: Any?): R? =
query(conn, q, {
it.use { rs ->
if (rs.next()) {
mapper(it)
} else {
null
}
}
}, *binds)
private fun bindValues(stmt: PreparedStatement, vararg binds: Any?) {
binds.withIndex().forEach {
val value = it.value
val i = it.index
when (value) {
is String -> stmt.setString(i + 1, value)
is LocalDate -> stmt.setDate(i + 1, Date.valueOf(value))
is Long -> stmt.setLong(i + 1, value)
is Int -> stmt.setInt(i + 1, value)
is Double -> stmt.setDouble(i + 1, value)
else -> stmt.setObject(i + 1, value)
}
}
}
}
@sazid
Copy link
Author

sazid commented Aug 30, 2021

Example usages:

// Usage 1
val count = one(conn, "SELECT count(tc_id) FROM test_cases WHERE tc_id=?", { it.getLong(1) }, id)

// Usage 2
val q = "SELECT section_path::text FROM product_sections WHERE section_id::text=? AND project_id=? AND team_id=?"
val sectionPath = one(conn, q, { rs -> rs.getString(1) }, tc.folder.toString(), tc.projectId, tc.teamId)

// Usage 3
val q = """SELECT ui.uid,
  ui.username,
  ui.full_name,
  pul.email
FROM user_info ui
  INNER JOIN pul
      ON pul.user_id = ui.uid
WHERE 
  username = ?
"""
val rowMapper: RowMapper<UserIdentity> = {
    UserIdentity(
            id = it.getLong("uid"),
            username = it.getString("username"),
            fullName = it.getString("full_name"),
    )
}
val user: UserIdentity = DBUtils.one(ds, q, rowMapper, username)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment