Skip to content

Commit

Permalink
Merge pull request #1939 from sideeffffect/hikari-different-effects
Browse files Browse the repository at this point in the history
Allow for different effects of HikariTransactor and its creation
  • Loading branch information
jatcwang authored Dec 18, 2023
2 parents ac44b7e + 5866c11 commit 9fa2f52
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 25 deletions.
2 changes: 1 addition & 1 deletion modules/docs/src/main/mdoc/docs/14-Managing-Connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ object HikariApp extends IOApp {
config.setPassword("")
config
}
xa <- HikariTransactor.fromHikariConfig[IO](hikariConfig)
xa <- HikariTransactor.fromHikariConfig[IO, IO](hikariConfig)
} yield xa


Expand Down
51 changes: 27 additions & 24 deletions modules/hikari/src/main/scala/doobie/hikari/HikariTransactor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,21 @@ object HikariTransactor {
}

/** Resource yielding an unconfigured `HikariTransactor`. */
def initial[M[_]: Async](
def initial[M0[_]: Sync, M[_]: Async](
connectEC: ExecutionContext,
logHandler: Option[LogHandler[M]] = None
): Resource[M, HikariTransactor[M]] = {
Resource.fromAutoCloseable(Sync[M].delay(new HikariDataSource))
): Resource[M0, HikariTransactor[M]] = {
Resource.fromAutoCloseable(Sync[M0].delay(new HikariDataSource))
.map(Transactor.fromDataSource[M](_, connectEC, logHandler))
}

/** Resource yielding a new `HikariTransactor` configured with the given Config.
* Unless you have a good reason, consider using `fromConfig` which creates the `connectEC` for you.
*/
def fromConfigCustomEc[M[_]: Async](
def fromConfigCustomEc[M0[_]: Sync, M[_]: Async](
config: Config,
connectEC: ExecutionContext,
logHandler: Option[LogHandler[M]] = None,
logHandler: Option[LogHandler[M]] = None,
dataSource: Option[DataSource] = None,
dataSourceProperties: Option[Properties] = None,
healthCheckProperties: Option[Properties] = None,
Expand All @@ -55,10 +55,10 @@ object HikariTransactor {
metricsTrackerFactory: Option[MetricsTrackerFactory] = None,
scheduledExecutor: Option[ScheduledExecutorService] = None,
threadFactory: Option[ThreadFactory] = None,
): Resource[M, HikariTransactor[M]] = {
): Resource[M0, HikariTransactor[M]] = {
Resource
.liftK(
Config.makeHikariConfig(
Config.makeHikariConfig[M0](
config = config,
dataSource = dataSource,
dataSourceProperties = dataSourceProperties,
Expand All @@ -70,13 +70,16 @@ object HikariTransactor {
threadFactory = threadFactory
)
)
.flatMap(fromHikariConfigCustomEc(_, connectEC, logHandler))
.flatMap(fromHikariConfigCustomEc[M0, M](_, connectEC, logHandler))
}

/** Resource yielding a new `HikariTransactor` configured with the given Config.
* The `connectEC` is created automatically, with the same size as the Hikari pool.
*
* @tparam M0 the effect to create a [[HikariTransactor]]
* @tparam M the effect under which the [[HikariTransactor]] runs
*/
def fromConfig[M[_]: Async](
def fromConfig[M0[_]: Sync, M[_]: Async](
config: Config,
logHandler: Option[LogHandler[M]] = None,
dataSource: Option[DataSource] = None,
Expand All @@ -87,10 +90,10 @@ object HikariTransactor {
metricsTrackerFactory: Option[MetricsTrackerFactory] = None,
scheduledExecutor: Option[ScheduledExecutorService] = None,
threadFactory: Option[ThreadFactory] = None,
): Resource[M, HikariTransactor[M]] = {
): Resource[M0, HikariTransactor[M]] = {
Resource
.liftK(
Config.makeHikariConfig(
Config.makeHikariConfig[M0](
config = config,
dataSource = dataSource,
dataSourceProperties = dataSourceProperties,
Expand All @@ -102,36 +105,36 @@ object HikariTransactor {
threadFactory = threadFactory
)
)
.flatMap(fromHikariConfig(_, logHandler))
.flatMap(fromHikariConfig[M0, M](_, logHandler))
}

/** Resource yielding a new `HikariTransactor` configured with the given HikariConfig.
* Unless you have a good reason, consider using [[fromHikariConfig]], it will be created automatically for you.
*/
def fromHikariConfigCustomEc[M[_]: Async](
def fromHikariConfigCustomEc[M0[_]: Sync, M[_]: Async](
hikariConfig: HikariConfig,
connectEC: ExecutionContext,
logHandler: Option[LogHandler[M]] = None
): Resource[M, HikariTransactor[M]] = Resource
.fromAutoCloseable(Sync[M].delay(new HikariDataSource(hikariConfig)))
): Resource[M0, HikariTransactor[M]] = Resource
.fromAutoCloseable(Sync[M0].delay(new HikariDataSource(hikariConfig)))
.map(Transactor.fromDataSource[M](_, connectEC, logHandler))

/** Resource yielding a new `HikariTransactor` configured with the given HikariConfig.
* The connection ExecutionContext (used for waiting for a connection from the connection pool) is created automatically, with the same size as the Hikari connection pool.
*/
def fromHikariConfig[M[_]: Async](
def fromHikariConfig[M0[_]: Sync, M[_]: Async](
hikariConfig: HikariConfig,
logHandler: Option[LogHandler[M]] = None
): Resource[M, HikariTransactor[M]] =
): Resource[M0, HikariTransactor[M]] =
for {
// to populate unset fields with default values, like `maximumPoolSize`
_ <- Sync[M].delay(hikariConfig.validate()).toResource
_ <- Sync[M0].delay(hikariConfig.validate()).toResource
// Note that the number of JDBC connections is usually limited by the underlying JDBC pool.
// You may therefore want to limit your connection pool to the same size as the underlying JDBC pool
// as any additional threads are guaranteed to be blocked.
// https://tpolecat.github.io/doobie/docs/14-Managing-Connections.html#about-threading
connectEC <- ExecutionContexts.fixedThreadPool(hikariConfig.getMaximumPoolSize)
result <- fromHikariConfigCustomEc(hikariConfig, connectEC, logHandler)
connectEC <- ExecutionContexts.fixedThreadPool[M0](hikariConfig.getMaximumPoolSize)
result <- fromHikariConfigCustomEc[M0, M](hikariConfig, connectEC, logHandler)
} yield result

/** Resource yielding a new `HikariTransactor` configured with the given info.
Expand All @@ -146,11 +149,11 @@ object HikariTransactor {
logHandler: Option[LogHandler[M]] = None
): Resource[M, HikariTransactor[M]] =
for {
_ <- Resource.eval(Async[M].delay(Class.forName(driverClassName)))
t <- initial[M](connectEC, logHandler)
_ <- Resource.eval {
_ <- Resource.eval(Sync[M].delay(Class.forName(driverClassName)))
t <- initial[M, M](connectEC, logHandler)
_ <- Resource.eval[M, Unit] {
t.configure { ds =>
Async[M].delay {
Sync[M].delay[Unit] {
ds setJdbcUrl url
ds setUsername user
ds setPassword pass
Expand Down

0 comments on commit 9fa2f52

Please sign in to comment.