The doobie.hi (High-level Interface) modules build upon the low-level doobie.free API but automatically handle resource management (closing Connections, PreparedStatements, and ResultSets) and logging. This is the recommended way to perform custom JDBC operations without the risk of resource leaks.
import cats.effect.IO
import cats.effect.unsafe.implicits.global // To allow .unsafeRunSync
import org.typelevel.doobie.Transactor
// Create the transactor
val xa: Transactor[IO] = Transactor.fromDriverManager[IO](
driver = "org.postgresql.Driver",
url = "jdbc:postgresql:world",
user = "postgres",
password = "password",
logHandler = None
)
import org.typelevel.doobie.HC // High-level API over java.sql.Connection
import org.typelevel.doobie.HRS // High-level API over java.sql.ResultSet
import org.typelevel.doobie.ConnectionIO
import org.typelevel.doobie.util.log.{LoggingInfo, Parameters}
import cats.effect.unsafe.implicits.global
import org.typelevel.doobie.util.unlabeled
val sql = "SELECT * FROM (VALUES (1, '1'), (2, '2'))"
val program: ConnectionIO[List[(Int, String)]] = HC.executeWithResultSet(
create = FC.prepareStatement(sql),
prep = FPS.unit,
exec = FPS.executeQuery,
process = HRS.list[(Int, String)],
loggingInfo = LoggingInfo(sql, Parameters.NonBatch(List.empty), label = unlabeled)
)
program.transact(xa).unsafeRunSync()