Skip to content

Commit

Permalink
Merge pull request #2079 from TalkingFoxMid/fix_query_cancellation_ca…
Browse files Browse the repository at this point in the history
…ncelable

fix query cancellation with cancelable
  • Loading branch information
jatcwang authored Aug 19, 2024
2 parents d1f84e6 + ed60a5f commit 3898e04
Show file tree
Hide file tree
Showing 30 changed files with 272 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
run: sbt +update

- name: Start up Postgres
run: docker-compose up -d
run: docker compose up -d

- name: Check Headers
run: sbt '++ ${{ matrix.scala }}' headerCheckAll
Expand Down
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ThisBuild / tlSonatypeUseLegacyHost := false
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("11"))
ThisBuild / githubWorkflowBuildPreamble ++= Seq(
WorkflowStep.Run(
commands = List("docker-compose up -d"),
commands = List("docker compose up -d"),
name = Some("Start up Postgres")
),
WorkflowStep.Sbt(
Expand Down Expand Up @@ -426,6 +426,7 @@ lazy val hikari = project
libraryDependencies ++= Seq(
// needs to be excluded, otherwise coursier may resolve slf4j-api 2 if > Java 11
"com.zaxxer" % "HikariCP" % hikariVersion exclude ("org.slf4j", "slf4j-api"),
"org.postgresql" % "postgresql" % postgresVersion % "test",
"com.h2database" % "h2" % h2Version % "test",
"org.slf4j" % "slf4j-api" % slf4jVersion,
"org.slf4j" % "slf4j-nop" % slf4jVersion % "test"
Expand Down
6 changes: 5 additions & 1 deletion modules/core/src/main/scala/doobie/hi/connection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ object connection {
}

createLogged
.bracket(ps => IFC.embed(ps, prepLogged *> execAndProcessLogged))(ps => IFC.embed(ps, IFPS.close))
.bracket(ps =>
WeakAsyncConnectionIO.cancelable(
IFC.embed(ps, prepLogged *> execAndProcessLogged),
IFC.embed(ps, IFPS.close)
))(IFC.embed(_, IFPS.close))
}

/** Execute a PreparedStatement query and provide rows from the ResultSet in chunks
Expand Down
17 changes: 11 additions & 6 deletions modules/core/src/test/scala/doobie/util/QueryLogSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
package doobie.util

import cats.syntax.all.*
import cats.effect.{IO, IOLocal}
import cats.effect.{IO, Ref}
import doobie.free.connection.ConnectionIO
import doobie.implicits.*
import doobie.util.log.Parameters.NonBatch
Expand All @@ -18,19 +18,24 @@ class QueryLogSuite extends munit.FunSuite with QueryLogSuitePlatform {

import cats.effect.unsafe.implicits.global

val ioLocal: IOLocal[LogEvent] =
IOLocal[LogEvent](null).unsafeRunSync()
val logEventRef: Ref[IO, LogEvent] =
Ref.of[IO, LogEvent](null).unsafeRunSync()

val xa = Transactor.fromDriverManager[IO](
"org.h2.Driver",
"jdbc:h2:mem:queryspec;DB_CLOSE_DELAY=-1",
"sa",
"",
logHandler = Some(ev => ioLocal.set(ev))
logHandler = Some(ev => logEventRef.set(ev))
)

def eventForCIO[A](cio: ConnectionIO[A]): LogEvent =
cio.transact(xa).attempt.flatMap(_ => ioLocal.get).unsafeRunSync()
def eventForCIO[A](cio: ConnectionIO[A]): LogEvent = {
for {
_ <- logEventRef.set(null)
_ <- cio.transact(xa).attempt
log <- logEventRef.get
} yield log
}.unsafeRunSync()

def successEventForCIO[A](cio: ConnectionIO[A]): Success =
eventForCIO(cio) match {
Expand Down
32 changes: 17 additions & 15 deletions modules/core/src/test/scala/doobie/util/UpdateLogSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

package doobie.util

import cats.effect.{IO, IOLocal}
import cats.effect.{IO, Ref}
import cats.syntax.all.*
import doobie.*
import doobie.implicits.*
Expand All @@ -18,28 +18,30 @@ class UpdateLogSuite extends munit.FunSuite {

import cats.effect.unsafe.implicits.global

val ioLocal: IOLocal[LogEvent] =
IOLocal[LogEvent](null).unsafeRunSync()
val logEventRef: Ref[IO, LogEvent] =
Ref.of[IO, LogEvent](null).unsafeRunSync()

val xa = Transactor.fromDriverManager[IO](
"org.h2.Driver",
"jdbc:h2:mem:queryspec;DB_CLOSE_DELAY=-1",
"sa",
"",
logHandler = Some(ev => ioLocal.set(ev))
logHandler = Some(ev => logEventRef.set(ev))
)

def eventForCIO[A](cio: ConnectionIO[A]): LogEvent =
(
sql"create table if not exists foo (c1 integer, c2 varchar)".update.run *> cio
)
.transact(xa)
.attempt
.flatMap { res =>
val _ = res
ioLocal.get
}
.unsafeRunSync()
def eventForCIO[A](cio: ConnectionIO[A]): LogEvent = {
logEventRef.set(null) *>
(
sql"create table if not exists foo (c1 integer, c2 varchar)".update.run *> cio
)
.transact(xa)
.attempt
.flatMap { res =>
val _ = res
logEventRef.get
}
}
.unsafeRunSync()

def successEventForCIO[A](cio: ConnectionIO[A]): Success =
eventForCIO(cio) match {
Expand Down
3 changes: 3 additions & 0 deletions modules/free/src/main/scala/doobie/WeakAsync.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import scala.concurrent.duration.FiniteDuration
trait WeakAsync[F[_]] extends Sync[F] {
def fromFuture[A](fut: F[Future[A]]): F[A]
def fromFutureCancelable[A](fut: F[(Future[A], F[Unit])]): F[A]
def cancelable[A](fa: F[A], fin: F[Unit]): F[A]
}

object WeakAsync {
Expand All @@ -39,6 +40,8 @@ object WeakAsync {
override def onCancel[A](fa: F[A], fin: F[Unit]): F[A] = F.onCancel(fa, fin)
override def fromFuture[A](fut: F[Future[A]]): F[A] = F.fromFuture(fut)
override def fromFutureCancelable[A](fut: F[(Future[A], F[Unit])]): F[A] = F.fromFutureCancelable(fut)

override def cancelable[A](fa: F[A], fin: F[Unit]): F[A] = F.cancelable(fa, fin)
}

/** Create a natural transformation for lifting an `Async` effect `F` into a `WeakAsync` effect `G`
Expand Down
6 changes: 6 additions & 0 deletions modules/free/src/main/scala/doobie/free/blob.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ object blob { module =>
def onCancel[A](fa: BlobIO[A], fin: BlobIO[Unit]): F[A]
def fromFuture[A](fut: BlobIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: BlobIO[(Future[A], BlobIO[Unit])]): F[A]
def cancelable[A](fa: BlobIO[A], fin: BlobIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// Blob
Expand Down Expand Up @@ -119,6 +120,9 @@ object blob { module =>
case class FromFutureCancelable[A](fut: BlobIO[(Future[A], BlobIO[Unit])]) extends BlobOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: BlobIO[A], fin: BlobIO[Unit]) extends BlobOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends BlobOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -181,6 +185,7 @@ object blob { module =>
def onCancel[A](fa: BlobIO[A], fin: BlobIO[Unit]) = FF.liftF[BlobOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: BlobIO[Future[A]]) = FF.liftF[BlobOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: BlobIO[(Future[A], BlobIO[Unit])]) = FF.liftF[BlobOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: BlobIO[A], fin: BlobIO[Unit]) = FF.liftF[BlobOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[BlobOp, Unit](PerformLogging(event))

// Smart constructors for Blob-specific operations.
Expand Down Expand Up @@ -216,6 +221,7 @@ object blob { module =>
override def onCancel[A](fa: BlobIO[A], fin: BlobIO[Unit]): BlobIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: BlobIO[Future[A]]): BlobIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: BlobIO[(Future[A], BlobIO[Unit])]): BlobIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: BlobIO[A], fin: BlobIO[Unit]): BlobIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidBlobIO[A : Monoid]: Monoid[BlobIO[A]] = new Monoid[BlobIO[A]] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ object callablestatement { module =>
def onCancel[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): F[A]
def fromFuture[A](fut: CallableStatementIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: CallableStatementIO[(Future[A], CallableStatementIO[Unit])]): F[A]
def cancelable[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// CallableStatement
Expand Down Expand Up @@ -362,6 +363,9 @@ object callablestatement { module =>
case class FromFutureCancelable[A](fut: CallableStatementIO[(Future[A], CallableStatementIO[Unit])]) extends CallableStatementOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]) extends CallableStatementOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends CallableStatementOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -1090,6 +1094,7 @@ object callablestatement { module =>
def onCancel[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]) = FF.liftF[CallableStatementOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: CallableStatementIO[Future[A]]) = FF.liftF[CallableStatementOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: CallableStatementIO[(Future[A], CallableStatementIO[Unit])]) = FF.liftF[CallableStatementOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]) = FF.liftF[CallableStatementOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[CallableStatementOp, Unit](PerformLogging(event))

// Smart constructors for CallableStatement-specific operations.
Expand Down Expand Up @@ -1347,6 +1352,7 @@ object callablestatement { module =>
override def onCancel[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): CallableStatementIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: CallableStatementIO[Future[A]]): CallableStatementIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: CallableStatementIO[(Future[A], CallableStatementIO[Unit])]): CallableStatementIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): CallableStatementIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidCallableStatementIO[A : Monoid]: Monoid[CallableStatementIO[A]] = new Monoid[CallableStatementIO[A]] {
Expand Down
6 changes: 6 additions & 0 deletions modules/free/src/main/scala/doobie/free/clob.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ object clob { module =>
def onCancel[A](fa: ClobIO[A], fin: ClobIO[Unit]): F[A]
def fromFuture[A](fut: ClobIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: ClobIO[(Future[A], ClobIO[Unit])]): F[A]
def cancelable[A](fa: ClobIO[A], fin: ClobIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// Clob
Expand Down Expand Up @@ -124,6 +125,9 @@ object clob { module =>
case class FromFutureCancelable[A](fut: ClobIO[(Future[A], ClobIO[Unit])]) extends ClobOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: ClobIO[A], fin: ClobIO[Unit]) extends ClobOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends ClobOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -192,6 +196,7 @@ object clob { module =>
def onCancel[A](fa: ClobIO[A], fin: ClobIO[Unit]) = FF.liftF[ClobOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: ClobIO[Future[A]]) = FF.liftF[ClobOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: ClobIO[(Future[A], ClobIO[Unit])]) = FF.liftF[ClobOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: ClobIO[A], fin: ClobIO[Unit]) = FF.liftF[ClobOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[ClobOp, Unit](PerformLogging(event))

// Smart constructors for Clob-specific operations.
Expand Down Expand Up @@ -229,6 +234,7 @@ object clob { module =>
override def onCancel[A](fa: ClobIO[A], fin: ClobIO[Unit]): ClobIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: ClobIO[Future[A]]): ClobIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: ClobIO[(Future[A], ClobIO[Unit])]): ClobIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: ClobIO[A], fin: ClobIO[Unit]): ClobIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidClobIO[A : Monoid]: Monoid[ClobIO[A]] = new Monoid[ClobIO[A]] {
Expand Down
6 changes: 6 additions & 0 deletions modules/free/src/main/scala/doobie/free/connection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ object connection { module =>
def onCancel[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): F[A]
def fromFuture[A](fut: ConnectionIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: ConnectionIO[(Future[A], ConnectionIO[Unit])]): F[A]
def cancelable[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// Connection
Expand Down Expand Up @@ -183,6 +184,9 @@ object connection { module =>
case class FromFutureCancelable[A](fut: ConnectionIO[(Future[A], ConnectionIO[Unit])]) extends ConnectionOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]) extends ConnectionOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends ConnectionOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -392,6 +396,7 @@ object connection { module =>
def onCancel[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]) = FF.liftF[ConnectionOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: ConnectionIO[Future[A]]) = FF.liftF[ConnectionOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: ConnectionIO[(Future[A], ConnectionIO[Unit])]) = FF.liftF[ConnectionOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]) = FF.liftF[ConnectionOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[ConnectionOp, Unit](PerformLogging(event))

// Smart constructors for Connection-specific operations.
Expand Down Expand Up @@ -476,6 +481,7 @@ object connection { module =>
override def onCancel[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): ConnectionIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: ConnectionIO[Future[A]]): ConnectionIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: ConnectionIO[(Future[A], ConnectionIO[Unit])]): ConnectionIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): ConnectionIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidConnectionIO[A : Monoid]: Monoid[ConnectionIO[A]] = new Monoid[ConnectionIO[A]] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ object databasemetadata { module =>
def onCancel[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): F[A]
def fromFuture[A](fut: DatabaseMetaDataIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: DatabaseMetaDataIO[(Future[A], DatabaseMetaDataIO[Unit])]): F[A]
def cancelable[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// DatabaseMetaData
Expand Down Expand Up @@ -290,6 +291,9 @@ object databasemetadata { module =>
case class FromFutureCancelable[A](fut: DatabaseMetaDataIO[(Future[A], DatabaseMetaDataIO[Unit])]) extends DatabaseMetaDataOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]) extends DatabaseMetaDataOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends DatabaseMetaDataOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -856,6 +860,7 @@ object databasemetadata { module =>
def onCancel[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]) = FF.liftF[DatabaseMetaDataOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: DatabaseMetaDataIO[Future[A]]) = FF.liftF[DatabaseMetaDataOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: DatabaseMetaDataIO[(Future[A], DatabaseMetaDataIO[Unit])]) = FF.liftF[DatabaseMetaDataOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]) = FF.liftF[DatabaseMetaDataOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[DatabaseMetaDataOp, Unit](PerformLogging(event))

// Smart constructors for DatabaseMetaData-specific operations.
Expand Down Expand Up @@ -1059,6 +1064,7 @@ object databasemetadata { module =>
override def onCancel[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): DatabaseMetaDataIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: DatabaseMetaDataIO[Future[A]]): DatabaseMetaDataIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: DatabaseMetaDataIO[(Future[A], DatabaseMetaDataIO[Unit])]): DatabaseMetaDataIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): DatabaseMetaDataIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidDatabaseMetaDataIO[A : Monoid]: Monoid[DatabaseMetaDataIO[A]] = new Monoid[DatabaseMetaDataIO[A]] {
Expand Down
6 changes: 6 additions & 0 deletions modules/free/src/main/scala/doobie/free/driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ object driver { module =>
def onCancel[A](fa: DriverIO[A], fin: DriverIO[Unit]): F[A]
def fromFuture[A](fut: DriverIO[Future[A]]): F[A]
def fromFutureCancelable[A](fut: DriverIO[(Future[A], DriverIO[Unit])]): F[A]
def cancelable[A](fa: DriverIO[A], fin: DriverIO[Unit]): F[A]
def performLogging(event: LogEvent): F[Unit]

// Driver
Expand Down Expand Up @@ -118,6 +119,9 @@ object driver { module =>
case class FromFutureCancelable[A](fut: DriverIO[(Future[A], DriverIO[Unit])]) extends DriverOp[A] {
def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut)
}
case class Cancelable[A](fa: DriverIO[A], fin: DriverIO[Unit]) extends DriverOp[A] {
def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin)
}
case class PerformLogging(event: LogEvent) extends DriverOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.performLogging(event)
}
Expand Down Expand Up @@ -168,6 +172,7 @@ object driver { module =>
def onCancel[A](fa: DriverIO[A], fin: DriverIO[Unit]) = FF.liftF[DriverOp, A](OnCancel(fa, fin))
def fromFuture[A](fut: DriverIO[Future[A]]) = FF.liftF[DriverOp, A](FromFuture(fut))
def fromFutureCancelable[A](fut: DriverIO[(Future[A], DriverIO[Unit])]) = FF.liftF[DriverOp, A](FromFutureCancelable(fut))
def cancelable[A](fa: DriverIO[A], fin: DriverIO[Unit]) = FF.liftF[DriverOp, A](Cancelable(fa, fin))
def performLogging(event: LogEvent) = FF.liftF[DriverOp, Unit](PerformLogging(event))

// Smart constructors for Driver-specific operations.
Expand Down Expand Up @@ -199,6 +204,7 @@ object driver { module =>
override def onCancel[A](fa: DriverIO[A], fin: DriverIO[Unit]): DriverIO[A] = module.onCancel(fa, fin)
override def fromFuture[A](fut: DriverIO[Future[A]]): DriverIO[A] = module.fromFuture(fut)
override def fromFutureCancelable[A](fut: DriverIO[(Future[A], DriverIO[Unit])]): DriverIO[A] = module.fromFutureCancelable(fut)
override def cancelable[A](fa: DriverIO[A], fin: DriverIO[Unit]): DriverIO[A] = module.cancelable(fa, fin)
}

implicit def MonoidDriverIO[A : Monoid]: Monoid[DriverIO[A]] = new Monoid[DriverIO[A]] {
Expand Down
Loading

0 comments on commit 3898e04

Please sign in to comment.