diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46c3b4e2c..3f00f3b10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/build.sbt b/build.sbt index 7bff9b0b1..92a88f1f4 100644 --- a/build.sbt +++ b/build.sbt @@ -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( @@ -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" diff --git a/modules/core/src/main/scala/doobie/hi/connection.scala b/modules/core/src/main/scala/doobie/hi/connection.scala index b94a0c7f6..885eabddf 100644 --- a/modules/core/src/main/scala/doobie/hi/connection.scala +++ b/modules/core/src/main/scala/doobie/hi/connection.scala @@ -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 diff --git a/modules/core/src/test/scala/doobie/util/QueryLogSuite.scala b/modules/core/src/test/scala/doobie/util/QueryLogSuite.scala index 68b4b1a41..fe95d9b02 100644 --- a/modules/core/src/test/scala/doobie/util/QueryLogSuite.scala +++ b/modules/core/src/test/scala/doobie/util/QueryLogSuite.scala @@ -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 @@ -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 { diff --git a/modules/core/src/test/scala/doobie/util/UpdateLogSuite.scala b/modules/core/src/test/scala/doobie/util/UpdateLogSuite.scala index ce924045e..aaf3b8a7c 100644 --- a/modules/core/src/test/scala/doobie/util/UpdateLogSuite.scala +++ b/modules/core/src/test/scala/doobie/util/UpdateLogSuite.scala @@ -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.* @@ -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 { diff --git a/modules/free/src/main/scala/doobie/WeakAsync.scala b/modules/free/src/main/scala/doobie/WeakAsync.scala index 5bbc44010..031ee928b 100644 --- a/modules/free/src/main/scala/doobie/WeakAsync.scala +++ b/modules/free/src/main/scala/doobie/WeakAsync.scala @@ -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 { @@ -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` diff --git a/modules/free/src/main/scala/doobie/free/blob.scala b/modules/free/src/main/scala/doobie/free/blob.scala index 64069275a..a5f7b42c8 100644 --- a/modules/free/src/main/scala/doobie/free/blob.scala +++ b/modules/free/src/main/scala/doobie/free/blob.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/callablestatement.scala b/modules/free/src/main/scala/doobie/free/callablestatement.scala index 7631b2bde..9c4e341a6 100644 --- a/modules/free/src/main/scala/doobie/free/callablestatement.scala +++ b/modules/free/src/main/scala/doobie/free/callablestatement.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/clob.scala b/modules/free/src/main/scala/doobie/free/clob.scala index e9060a211..76d773cc3 100644 --- a/modules/free/src/main/scala/doobie/free/clob.scala +++ b/modules/free/src/main/scala/doobie/free/clob.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/connection.scala b/modules/free/src/main/scala/doobie/free/connection.scala index 75b3b7395..75e89dead 100644 --- a/modules/free/src/main/scala/doobie/free/connection.scala +++ b/modules/free/src/main/scala/doobie/free/connection.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/databasemetadata.scala b/modules/free/src/main/scala/doobie/free/databasemetadata.scala index a56a4fadc..0703e4fab 100644 --- a/modules/free/src/main/scala/doobie/free/databasemetadata.scala +++ b/modules/free/src/main/scala/doobie/free/databasemetadata.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/driver.scala b/modules/free/src/main/scala/doobie/free/driver.scala index 04095f033..5a1eb880e 100644 --- a/modules/free/src/main/scala/doobie/free/driver.scala +++ b/modules/free/src/main/scala/doobie/free/driver.scala @@ -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 @@ -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) } @@ -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. @@ -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]] { diff --git a/modules/free/src/main/scala/doobie/free/kleisliinterpreter.scala b/modules/free/src/main/scala/doobie/free/kleisliinterpreter.scala index ddf042a5a..e803cb35f 100644 --- a/modules/free/src/main/scala/doobie/free/kleisliinterpreter.scala +++ b/modules/free/src/main/scala/doobie/free/kleisliinterpreter.scala @@ -136,6 +136,9 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W def fromFutureCancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fut: Free[G, (Future[A], Free[G, Unit])]): Kleisli[M, J, A] = Kleisli(j => asyncM.fromFutureCancelable(fut.map { case (f, g) => (f, g.foldMap(interpreter).run(j)) }.foldMap(interpreter).run(j)) ) + def cancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fa: Free[G, A], fin: Free[G, Unit]): Kleisli[M, J, A] = Kleisli (j => + asyncM.cancelable(fa.foldMap(interpreter).run(j), fin.foldMap(interpreter).run(j)) + ) def embed[J, A](e: Embedded[A]): Kleisli[M, J, A] = e match { case Embedded.NClob(j, fa) => Kleisli(_ => fa.foldMap(NClobInterpreter).run(j)) @@ -177,6 +180,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: NClobIO[A], fin: NClobIO[Unit]): Kleisli[M, NClob, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: NClobIO[Future[A]]): Kleisli[M, NClob, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: NClobIO[(Future[A], NClobIO[Unit])]): Kleisli[M, NClob, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: NClobIO[A], fin: NClobIO[Unit]): Kleisli[M, NClob, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def free: Kleisli[M, NClob, Unit] = primitive(_.free) @@ -217,6 +222,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: BlobIO[A], fin: BlobIO[Unit]): Kleisli[M, Blob, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: BlobIO[Future[A]]): Kleisli[M, Blob, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: BlobIO[(Future[A], BlobIO[Unit])]): Kleisli[M, Blob, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: BlobIO[A], fin: BlobIO[Unit]): Kleisli[M, Blob, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def free: Kleisli[M, Blob, Unit] = primitive(_.free) @@ -255,6 +262,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: ClobIO[A], fin: ClobIO[Unit]): Kleisli[M, Clob, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: ClobIO[Future[A]]): Kleisli[M, Clob, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: ClobIO[(Future[A], ClobIO[Unit])]): Kleisli[M, Clob, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: ClobIO[A], fin: ClobIO[Unit]): Kleisli[M, Clob, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def free: Kleisli[M, Clob, Unit] = primitive(_.free) @@ -295,6 +304,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): Kleisli[M, DatabaseMetaData, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: DatabaseMetaDataIO[Future[A]]): Kleisli[M, DatabaseMetaData, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: DatabaseMetaDataIO[(Future[A], DatabaseMetaDataIO[Unit])]): Kleisli[M, DatabaseMetaData, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: DatabaseMetaDataIO[A], fin: DatabaseMetaDataIO[Unit]): Kleisli[M, DatabaseMetaData, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def allProceduresAreCallable: Kleisli[M, DatabaseMetaData, Boolean] = primitive(_.allProceduresAreCallable) @@ -501,6 +512,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: DriverIO[A], fin: DriverIO[Unit]): Kleisli[M, Driver, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: DriverIO[Future[A]]): Kleisli[M, Driver, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: DriverIO[(Future[A], DriverIO[Unit])]): Kleisli[M, Driver, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: DriverIO[A], fin: DriverIO[Unit]): Kleisli[M, Driver, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def acceptsURL(a: String) = primitive(_.acceptsURL(a)) @@ -535,6 +548,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: RefIO[A], fin: RefIO[Unit]): Kleisli[M, Ref, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: RefIO[Future[A]]): Kleisli[M, Ref, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: RefIO[(Future[A], RefIO[Unit])]): Kleisli[M, Ref, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: RefIO[A], fin: RefIO[Unit]): Kleisli[M, Ref, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def getBaseTypeName: Kleisli[M, Ref, String] = primitive(_.getBaseTypeName) @@ -566,6 +581,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): Kleisli[M, SQLData, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: SQLDataIO[Future[A]]): Kleisli[M, SQLData, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: SQLDataIO[(Future[A], SQLDataIO[Unit])]): Kleisli[M, SQLData, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): Kleisli[M, SQLData, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def getSQLTypeName: Kleisli[M, SQLData, String] = primitive(_.getSQLTypeName) @@ -596,6 +613,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): Kleisli[M, SQLInput, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: SQLInputIO[Future[A]]): Kleisli[M, SQLInput, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: SQLInputIO[(Future[A], SQLInputIO[Unit])]): Kleisli[M, SQLInput, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): Kleisli[M, SQLInput, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def readArray: Kleisli[M, SQLInput, SqlArray] = primitive(_.readArray) @@ -651,6 +670,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): Kleisli[M, SQLOutput, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: SQLOutputIO[Future[A]]): Kleisli[M, SQLOutput, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: SQLOutputIO[(Future[A], SQLOutputIO[Unit])]): Kleisli[M, SQLOutput, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): Kleisli[M, SQLOutput, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def writeArray(a: SqlArray) = primitive(_.writeArray(a)) @@ -706,6 +727,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): Kleisli[M, Connection, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: ConnectionIO[Future[A]]): Kleisli[M, Connection, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: ConnectionIO[(Future[A], ConnectionIO[Unit])]): Kleisli[M, Connection, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: ConnectionIO[A], fin: ConnectionIO[Unit]): Kleisli[M, Connection, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def abort(a: Executor) = primitive(_.abort(a)) @@ -793,6 +816,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: StatementIO[A], fin: StatementIO[Unit]): Kleisli[M, Statement, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: StatementIO[Future[A]]): Kleisli[M, Statement, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: StatementIO[(Future[A], StatementIO[Unit])]): Kleisli[M, Statement, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: StatementIO[A], fin: StatementIO[Unit]): Kleisli[M, Statement, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def addBatch(a: String) = primitive(_.addBatch(a)) @@ -876,6 +901,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): Kleisli[M, PreparedStatement, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: PreparedStatementIO[Future[A]]): Kleisli[M, PreparedStatement, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: PreparedStatementIO[(Future[A], PreparedStatementIO[Unit])]): Kleisli[M, PreparedStatement, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): Kleisli[M, PreparedStatement, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def addBatch: Kleisli[M, PreparedStatement, Unit] = primitive(_.addBatch) @@ -1016,6 +1043,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): Kleisli[M, CallableStatement, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: CallableStatementIO[Future[A]]): Kleisli[M, CallableStatement, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: CallableStatementIO[(Future[A], CallableStatementIO[Unit])]): Kleisli[M, CallableStatement, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: CallableStatementIO[A], fin: CallableStatementIO[Unit]): Kleisli[M, CallableStatement, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def addBatch: Kleisli[M, CallableStatement, Unit] = primitive(_.addBatch) @@ -1276,6 +1305,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): Kleisli[M, ResultSet, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: ResultSetIO[Future[A]]): Kleisli[M, ResultSet, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: ResultSetIO[(Future[A], ResultSetIO[Unit])]): Kleisli[M, ResultSet, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): Kleisli[M, ResultSet, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def absolute(a: Int) = primitive(_.absolute(a)) diff --git a/modules/free/src/main/scala/doobie/free/nclob.scala b/modules/free/src/main/scala/doobie/free/nclob.scala index d89fbb869..d6be4b115 100644 --- a/modules/free/src/main/scala/doobie/free/nclob.scala +++ b/modules/free/src/main/scala/doobie/free/nclob.scala @@ -63,6 +63,7 @@ object nclob { module => def onCancel[A](fa: NClobIO[A], fin: NClobIO[Unit]): F[A] def fromFuture[A](fut: NClobIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: NClobIO[(Future[A], NClobIO[Unit])]): F[A] + def cancelable[A](fa: NClobIO[A], fin: NClobIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // NClob @@ -125,6 +126,9 @@ object nclob { module => case class FromFutureCancelable[A](fut: NClobIO[(Future[A], NClobIO[Unit])]) extends NClobOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: NClobIO[A], fin: NClobIO[Unit]) extends NClobOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends NClobOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -193,6 +197,7 @@ object nclob { module => def onCancel[A](fa: NClobIO[A], fin: NClobIO[Unit]) = FF.liftF[NClobOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: NClobIO[Future[A]]) = FF.liftF[NClobOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: NClobIO[(Future[A], NClobIO[Unit])]) = FF.liftF[NClobOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: NClobIO[A], fin: NClobIO[Unit]) = FF.liftF[NClobOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[NClobOp, Unit](PerformLogging(event)) // Smart constructors for NClob-specific operations. @@ -230,6 +235,7 @@ object nclob { module => override def onCancel[A](fa: NClobIO[A], fin: NClobIO[Unit]): NClobIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: NClobIO[Future[A]]): NClobIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: NClobIO[(Future[A], NClobIO[Unit])]): NClobIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: NClobIO[A], fin: NClobIO[Unit]): NClobIO[A] = module.cancelable(fa, fin) } implicit def MonoidNClobIO[A : Monoid]: Monoid[NClobIO[A]] = new Monoid[NClobIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/preparedstatement.scala b/modules/free/src/main/scala/doobie/free/preparedstatement.scala index 69b25cbe9..57354d279 100644 --- a/modules/free/src/main/scala/doobie/free/preparedstatement.scala +++ b/modules/free/src/main/scala/doobie/free/preparedstatement.scala @@ -80,6 +80,7 @@ object preparedstatement { module => def onCancel[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): F[A] def fromFuture[A](fut: PreparedStatementIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: PreparedStatementIO[(Future[A], PreparedStatementIO[Unit])]): F[A] + def cancelable[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // PreparedStatement @@ -242,6 +243,9 @@ object preparedstatement { module => case class FromFutureCancelable[A](fut: PreparedStatementIO[(Future[A], PreparedStatementIO[Unit])]) extends PreparedStatementOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]) extends PreparedStatementOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends PreparedStatementOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -610,6 +614,7 @@ object preparedstatement { module => def onCancel[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]) = FF.liftF[PreparedStatementOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: PreparedStatementIO[Future[A]]) = FF.liftF[PreparedStatementOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: PreparedStatementIO[(Future[A], PreparedStatementIO[Unit])]) = FF.liftF[PreparedStatementOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]) = FF.liftF[PreparedStatementOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[PreparedStatementOp, Unit](PerformLogging(event)) // Smart constructors for PreparedStatement-specific operations. @@ -747,6 +752,7 @@ object preparedstatement { module => override def onCancel[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): PreparedStatementIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: PreparedStatementIO[Future[A]]): PreparedStatementIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: PreparedStatementIO[(Future[A], PreparedStatementIO[Unit])]): PreparedStatementIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: PreparedStatementIO[A], fin: PreparedStatementIO[Unit]): PreparedStatementIO[A] = module.cancelable(fa, fin) } implicit def MonoidPreparedStatementIO[A : Monoid]: Monoid[PreparedStatementIO[A]] = new Monoid[PreparedStatementIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/ref.scala b/modules/free/src/main/scala/doobie/free/ref.scala index e1c8da153..c7dbdc988 100644 --- a/modules/free/src/main/scala/doobie/free/ref.scala +++ b/modules/free/src/main/scala/doobie/free/ref.scala @@ -58,6 +58,7 @@ object ref { module => def onCancel[A](fa: RefIO[A], fin: RefIO[Unit]): F[A] def fromFuture[A](fut: RefIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: RefIO[(Future[A], RefIO[Unit])]): F[A] + def cancelable[A](fa: RefIO[A], fin: RefIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // Ref @@ -111,6 +112,9 @@ object ref { module => case class FromFutureCancelable[A](fut: RefIO[(Future[A], RefIO[Unit])]) extends RefOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: RefIO[A], fin: RefIO[Unit]) extends RefOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends RefOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -152,6 +156,7 @@ object ref { module => def onCancel[A](fa: RefIO[A], fin: RefIO[Unit]) = FF.liftF[RefOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: RefIO[Future[A]]) = FF.liftF[RefOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: RefIO[(Future[A], RefIO[Unit])]) = FF.liftF[RefOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: RefIO[A], fin: RefIO[Unit]) = FF.liftF[RefOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[RefOp, Unit](PerformLogging(event)) // Smart constructors for Ref-specific operations. @@ -180,6 +185,7 @@ object ref { module => override def onCancel[A](fa: RefIO[A], fin: RefIO[Unit]): RefIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: RefIO[Future[A]]): RefIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: RefIO[(Future[A], RefIO[Unit])]): RefIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: RefIO[A], fin: RefIO[Unit]): RefIO[A] = module.cancelable(fa, fin) } implicit def MonoidRefIO[A : Monoid]: Monoid[RefIO[A]] = new Monoid[RefIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/resultset.scala b/modules/free/src/main/scala/doobie/free/resultset.scala index 85866f3d5..57bc94a28 100644 --- a/modules/free/src/main/scala/doobie/free/resultset.scala +++ b/modules/free/src/main/scala/doobie/free/resultset.scala @@ -78,6 +78,7 @@ object resultset { module => def onCancel[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): F[A] def fromFuture[A](fut: ResultSetIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: ResultSetIO[(Future[A], ResultSetIO[Unit])]): F[A] + def cancelable[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // ResultSet @@ -318,6 +319,9 @@ object resultset { module => case class FromFutureCancelable[A](fut: ResultSetIO[(Future[A], ResultSetIO[Unit])]) extends ResultSetOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]) extends ResultSetOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends ResultSetOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -920,6 +924,7 @@ object resultset { module => def onCancel[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]) = FF.liftF[ResultSetOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: ResultSetIO[Future[A]]) = FF.liftF[ResultSetOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: ResultSetIO[(Future[A], ResultSetIO[Unit])]) = FF.liftF[ResultSetOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]) = FF.liftF[ResultSetOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[ResultSetOp, Unit](PerformLogging(event)) // Smart constructors for ResultSet-specific operations. @@ -1135,6 +1140,7 @@ object resultset { module => override def onCancel[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): ResultSetIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: ResultSetIO[Future[A]]): ResultSetIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: ResultSetIO[(Future[A], ResultSetIO[Unit])]): ResultSetIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: ResultSetIO[A], fin: ResultSetIO[Unit]): ResultSetIO[A] = module.cancelable(fa, fin) } implicit def MonoidResultSetIO[A : Monoid]: Monoid[ResultSetIO[A]] = new Monoid[ResultSetIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/sqldata.scala b/modules/free/src/main/scala/doobie/free/sqldata.scala index dcf868cec..f0de890d3 100644 --- a/modules/free/src/main/scala/doobie/free/sqldata.scala +++ b/modules/free/src/main/scala/doobie/free/sqldata.scala @@ -60,6 +60,7 @@ object sqldata { module => def onCancel[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): F[A] def fromFuture[A](fut: SQLDataIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: SQLDataIO[(Future[A], SQLDataIO[Unit])]): F[A] + def cancelable[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // SQLData @@ -112,6 +113,9 @@ object sqldata { module => case class FromFutureCancelable[A](fut: SQLDataIO[(Future[A], SQLDataIO[Unit])]) extends SQLDataOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]) extends SQLDataOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends SQLDataOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -150,6 +154,7 @@ object sqldata { module => def onCancel[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]) = FF.liftF[SQLDataOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: SQLDataIO[Future[A]]) = FF.liftF[SQLDataOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: SQLDataIO[(Future[A], SQLDataIO[Unit])]) = FF.liftF[SQLDataOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]) = FF.liftF[SQLDataOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[SQLDataOp, Unit](PerformLogging(event)) // Smart constructors for SQLData-specific operations. @@ -177,6 +182,7 @@ object sqldata { module => override def onCancel[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): SQLDataIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: SQLDataIO[Future[A]]): SQLDataIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: SQLDataIO[(Future[A], SQLDataIO[Unit])]): SQLDataIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: SQLDataIO[A], fin: SQLDataIO[Unit]): SQLDataIO[A] = module.cancelable(fa, fin) } implicit def MonoidSQLDataIO[A : Monoid]: Monoid[SQLDataIO[A]] = new Monoid[SQLDataIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/sqlinput.scala b/modules/free/src/main/scala/doobie/free/sqlinput.scala index bdd18d1ea..ef718046e 100644 --- a/modules/free/src/main/scala/doobie/free/sqlinput.scala +++ b/modules/free/src/main/scala/doobie/free/sqlinput.scala @@ -73,6 +73,7 @@ object sqlinput { module => def onCancel[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): F[A] def fromFuture[A](fut: SQLInputIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: SQLInputIO[(Future[A], SQLInputIO[Unit])]): F[A] + def cancelable[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // SQLInput @@ -150,6 +151,9 @@ object sqlinput { module => case class FromFutureCancelable[A](fut: SQLInputIO[(Future[A], SQLInputIO[Unit])]) extends SQLInputOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]) extends SQLInputOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends SQLInputOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -263,6 +267,7 @@ object sqlinput { module => def onCancel[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]) = FF.liftF[SQLInputOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: SQLInputIO[Future[A]]) = FF.liftF[SQLInputOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: SQLInputIO[(Future[A], SQLInputIO[Unit])]) = FF.liftF[SQLInputOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]) = FF.liftF[SQLInputOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[SQLInputOp, Unit](PerformLogging(event)) // Smart constructors for SQLInput-specific operations. @@ -315,6 +320,7 @@ object sqlinput { module => override def onCancel[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): SQLInputIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: SQLInputIO[Future[A]]): SQLInputIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: SQLInputIO[(Future[A], SQLInputIO[Unit])]): SQLInputIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: SQLInputIO[A], fin: SQLInputIO[Unit]): SQLInputIO[A] = module.cancelable(fa, fin) } implicit def MonoidSQLInputIO[A : Monoid]: Monoid[SQLInputIO[A]] = new Monoid[SQLInputIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/sqloutput.scala b/modules/free/src/main/scala/doobie/free/sqloutput.scala index 4dff367c6..1897b3ba6 100644 --- a/modules/free/src/main/scala/doobie/free/sqloutput.scala +++ b/modules/free/src/main/scala/doobie/free/sqloutput.scala @@ -75,6 +75,7 @@ object sqloutput { module => def onCancel[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): F[A] def fromFuture[A](fut: SQLOutputIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: SQLOutputIO[(Future[A], SQLOutputIO[Unit])]): F[A] + def cancelable[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // SQLOutput @@ -152,6 +153,9 @@ object sqloutput { module => case class FromFutureCancelable[A](fut: SQLOutputIO[(Future[A], SQLOutputIO[Unit])]) extends SQLOutputOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]) extends SQLOutputOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends SQLOutputOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -265,6 +269,7 @@ object sqloutput { module => def onCancel[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]) = FF.liftF[SQLOutputOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: SQLOutputIO[Future[A]]) = FF.liftF[SQLOutputOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: SQLOutputIO[(Future[A], SQLOutputIO[Unit])]) = FF.liftF[SQLOutputOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]) = FF.liftF[SQLOutputOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[SQLOutputOp, Unit](PerformLogging(event)) // Smart constructors for SQLOutput-specific operations. @@ -317,6 +322,7 @@ object sqloutput { module => override def onCancel[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): SQLOutputIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: SQLOutputIO[Future[A]]): SQLOutputIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: SQLOutputIO[(Future[A], SQLOutputIO[Unit])]): SQLOutputIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: SQLOutputIO[A], fin: SQLOutputIO[Unit]): SQLOutputIO[A] = module.cancelable(fa, fin) } implicit def MonoidSQLOutputIO[A : Monoid]: Monoid[SQLOutputIO[A]] = new Monoid[SQLOutputIO[A]] { diff --git a/modules/free/src/main/scala/doobie/free/statement.scala b/modules/free/src/main/scala/doobie/free/statement.scala index 70f3a7bc6..e75ee19ba 100644 --- a/modules/free/src/main/scala/doobie/free/statement.scala +++ b/modules/free/src/main/scala/doobie/free/statement.scala @@ -62,6 +62,7 @@ object statement { module => def onCancel[A](fa: StatementIO[A], fin: StatementIO[Unit]): F[A] def fromFuture[A](fut: StatementIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: StatementIO[(Future[A], StatementIO[Unit])]): F[A] + def cancelable[A](fa: StatementIO[A], fin: StatementIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // Statement @@ -167,6 +168,9 @@ object statement { module => case class FromFutureCancelable[A](fut: StatementIO[(Future[A], StatementIO[Unit])]) extends StatementOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: StatementIO[A], fin: StatementIO[Unit]) extends StatementOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends StatementOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -364,6 +368,7 @@ object statement { module => def onCancel[A](fa: StatementIO[A], fin: StatementIO[Unit]) = FF.liftF[StatementOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: StatementIO[Future[A]]) = FF.liftF[StatementOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: StatementIO[(Future[A], StatementIO[Unit])]) = FF.liftF[StatementOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: StatementIO[A], fin: StatementIO[Unit]) = FF.liftF[StatementOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[StatementOp, Unit](PerformLogging(event)) // Smart constructors for Statement-specific operations. @@ -444,6 +449,7 @@ object statement { module => override def onCancel[A](fa: StatementIO[A], fin: StatementIO[Unit]): StatementIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: StatementIO[Future[A]]): StatementIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: StatementIO[(Future[A], StatementIO[Unit])]): StatementIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: StatementIO[A], fin: StatementIO[Unit]): StatementIO[A] = module.cancelable(fa, fin) } implicit def MonoidStatementIO[A : Monoid]: Monoid[StatementIO[A]] = new Monoid[StatementIO[A]] { diff --git a/modules/hikari/src/test/scala/doobie/HikariQueryCancellationSuite.scala b/modules/hikari/src/test/scala/doobie/HikariQueryCancellationSuite.scala new file mode 100644 index 000000000..7c2a6af7c --- /dev/null +++ b/modules/hikari/src/test/scala/doobie/HikariQueryCancellationSuite.scala @@ -0,0 +1,56 @@ +// Copyright (c) 2013-2020 Rob Norris and Contributors +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package doobie + +import cats.effect.* +import cats.effect.unsafe.implicits.global +import com.zaxxer.hikari.HikariConfig +import doobie.hikari.HikariTransactor +import doobie.implicits.* +import doobie.util.transactor + +import scala.concurrent.duration.DurationInt + +class HikariQueryCancellationSuite extends munit.FunSuite { + + // Typically you construct a transactor this way, using lifetime-managed thread pools. + val transactorRes: Resource[IO, Transactor[IO]] = + (for { + hikariConfig <- Resource.pure { + val config = new HikariConfig() + config.setDriverClassName("org.postgresql.Driver") + config.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres") + config.setUsername("postgres") + config.setPassword("password") + config.setMaximumPoolSize(2) + config + } + transactor <- HikariTransactor.fromHikariConfig[IO](hikariConfig) + } yield transactor) + .map(_.copy(strategy0 = transactor.Strategy.void)) + + test("Query cancel with Hikari") { + val insert = for { + _ <- sql"CREATE TABLE if not exists blah (i text)".update.run + _ <- sql"truncate table blah".update.run + _ <- sql"INSERT INTO blah values ('1')".update.run + _ <- sql"INSERT INTO blah select concat(2, pg_sleep(1))".update.run + } yield () + val scenario = transactorRes.use { xa => + for { + fiber <- insert.transact(xa).start + _ <- IO.sleep(200.millis) *> fiber.cancel + _ <- IO.sleep(3.second) + _ <- fiber.join.attempt + result <- sql"select * from blah order by i".query[String].to[List].transact(xa) + } yield { + assertEquals(result, List("1")) + } + } + + scenario.unsafeRunSync() + } + +} diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/copyin.scala b/modules/postgres/src/main/scala/doobie/postgres/free/copyin.scala index 0d9fc61a6..2348214c7 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/copyin.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/copyin.scala @@ -58,6 +58,7 @@ object copyin { module => def onCancel[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): F[A] def fromFuture[A](fut: CopyInIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: CopyInIO[(Future[A], CopyInIO[Unit])]): F[A] + def cancelable[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // PGCopyIn @@ -117,6 +118,9 @@ object copyin { module => case class FromFutureCancelable[A](fut: CopyInIO[(Future[A], CopyInIO[Unit])]) extends CopyInOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: CopyInIO[A], fin: CopyInIO[Unit]) extends CopyInOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends CopyInOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -176,6 +180,7 @@ object copyin { module => def onCancel[A](fa: CopyInIO[A], fin: CopyInIO[Unit]) = FF.liftF[CopyInOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: CopyInIO[Future[A]]) = FF.liftF[CopyInOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: CopyInIO[(Future[A], CopyInIO[Unit])]) = FF.liftF[CopyInOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: CopyInIO[A], fin: CopyInIO[Unit]) = FF.liftF[CopyInOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[CopyInOp, Unit](PerformLogging(event)) // Smart constructors for CopyIn-specific operations. @@ -210,6 +215,7 @@ object copyin { module => override def onCancel[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): CopyInIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: CopyInIO[Future[A]]): CopyInIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: CopyInIO[(Future[A], CopyInIO[Unit])]): CopyInIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): CopyInIO[A] = module.cancelable(fa, fin) } implicit def MonoidCopyInIO[A : Monoid]: Monoid[CopyInIO[A]] = new Monoid[CopyInIO[A]] { diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/copymanager.scala b/modules/postgres/src/main/scala/doobie/postgres/free/copymanager.scala index a411bdf02..1a22e0887 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/copymanager.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/copymanager.scala @@ -66,6 +66,7 @@ object copymanager { module => def onCancel[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): F[A] def fromFuture[A](fut: CopyManagerIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: CopyManagerIO[(Future[A], CopyManagerIO[Unit])]): F[A] + def cancelable[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // PGCopyManager @@ -125,6 +126,9 @@ object copymanager { module => case class FromFutureCancelable[A](fut: CopyManagerIO[(Future[A], CopyManagerIO[Unit])]) extends CopyManagerOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]) extends CopyManagerOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends CopyManagerOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -184,6 +188,7 @@ object copymanager { module => def onCancel[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]) = FF.liftF[CopyManagerOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: CopyManagerIO[Future[A]]) = FF.liftF[CopyManagerOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: CopyManagerIO[(Future[A], CopyManagerIO[Unit])]) = FF.liftF[CopyManagerOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]) = FF.liftF[CopyManagerOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[CopyManagerOp, Unit](PerformLogging(event)) // Smart constructors for CopyManager-specific operations. @@ -218,6 +223,7 @@ object copymanager { module => override def onCancel[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): CopyManagerIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: CopyManagerIO[Future[A]]): CopyManagerIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: CopyManagerIO[(Future[A], CopyManagerIO[Unit])]): CopyManagerIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): CopyManagerIO[A] = module.cancelable(fa, fin) } implicit def MonoidCopyManagerIO[A : Monoid]: Monoid[CopyManagerIO[A]] = new Monoid[CopyManagerIO[A]] { diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/copyout.scala b/modules/postgres/src/main/scala/doobie/postgres/free/copyout.scala index 6c283f4a0..04184e1ba 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/copyout.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/copyout.scala @@ -57,6 +57,7 @@ object copyout { module => def onCancel[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): F[A] def fromFuture[A](fut: CopyOutIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: CopyOutIO[(Future[A], CopyOutIO[Unit])]): F[A] + def cancelable[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // PGCopyOut @@ -114,6 +115,9 @@ object copyout { module => case class FromFutureCancelable[A](fut: CopyOutIO[(Future[A], CopyOutIO[Unit])]) extends CopyOutOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]) extends CopyOutOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends CopyOutOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -167,6 +171,7 @@ object copyout { module => def onCancel[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]) = FF.liftF[CopyOutOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: CopyOutIO[Future[A]]) = FF.liftF[CopyOutOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: CopyOutIO[(Future[A], CopyOutIO[Unit])]) = FF.liftF[CopyOutOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]) = FF.liftF[CopyOutOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[CopyOutOp, Unit](PerformLogging(event)) // Smart constructors for CopyOut-specific operations. @@ -199,6 +204,7 @@ object copyout { module => override def onCancel[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): CopyOutIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: CopyOutIO[Future[A]]): CopyOutIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: CopyOutIO[(Future[A], CopyOutIO[Unit])]): CopyOutIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): CopyOutIO[A] = module.cancelable(fa, fin) } implicit def MonoidCopyOutIO[A : Monoid]: Monoid[CopyOutIO[A]] = new Monoid[CopyOutIO[A]] { diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/kleisliinterpreter.scala b/modules/postgres/src/main/scala/doobie/postgres/free/kleisliinterpreter.scala index d4b0db91c..f6164fbd6 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/kleisliinterpreter.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/kleisliinterpreter.scala @@ -99,6 +99,9 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W def fromFutureCancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fut: Free[G, (Future[A], Free[G, Unit])]): Kleisli[M, J, A] = Kleisli(j => asyncM.fromFutureCancelable(fut.map { case (f, g) => (f, g.foldMap(interpreter).run(j)) }.foldMap(interpreter).run(j)) ) + def cancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fa: Free[G, A], fin: Free[G, Unit]): Kleisli[M, J, A] = Kleisli (j => + asyncM.cancelable(fa.foldMap(interpreter).run(j), fin.foldMap(interpreter).run(j)) + ) def embed[J, A](e: Embedded[A]): Kleisli[M, J, A] = e match { case Embedded.CopyIn(j, fa) => Kleisli(_ => fa.foldMap(CopyInInterpreter).run(j)) @@ -132,6 +135,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): Kleisli[M, PGCopyIn, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: CopyInIO[Future[A]]): Kleisli[M, PGCopyIn, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: CopyInIO[(Future[A], CopyInIO[Unit])]): Kleisli[M, PGCopyIn, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: CopyInIO[A], fin: CopyInIO[Unit]): Kleisli[M, PGCopyIn, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def cancelCopy: Kleisli[M, PGCopyIn, Unit] = primitive(_.cancelCopy) @@ -169,6 +174,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): Kleisli[M, PGCopyManager, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: CopyManagerIO[Future[A]]): Kleisli[M, PGCopyManager, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: CopyManagerIO[(Future[A], CopyManagerIO[Unit])]): Kleisli[M, PGCopyManager, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: CopyManagerIO[A], fin: CopyManagerIO[Unit]): Kleisli[M, PGCopyManager, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def copyDual(a: String) = primitive(_.copyDual(a)) @@ -206,6 +213,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): Kleisli[M, PGCopyOut, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: CopyOutIO[Future[A]]): Kleisli[M, PGCopyOut, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: CopyOutIO[(Future[A], CopyOutIO[Unit])]): Kleisli[M, PGCopyOut, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: CopyOutIO[A], fin: CopyOutIO[Unit]): Kleisli[M, PGCopyOut, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def cancelCopy: Kleisli[M, PGCopyOut, Unit] = primitive(_.cancelCopy) @@ -241,6 +250,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): Kleisli[M, LargeObject, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: LargeObjectIO[Future[A]]): Kleisli[M, LargeObject, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: LargeObjectIO[(Future[A], LargeObjectIO[Unit])]): Kleisli[M, LargeObject, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): Kleisli[M, LargeObject, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def close: Kleisli[M, LargeObject, Unit] = primitive(_.close) @@ -289,6 +300,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): Kleisli[M, LargeObjectManager, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: LargeObjectManagerIO[Future[A]]): Kleisli[M, LargeObjectManager, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: LargeObjectManagerIO[(Future[A], LargeObjectManagerIO[Unit])]): Kleisli[M, LargeObjectManager, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): Kleisli[M, LargeObjectManager, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def createLO: Kleisli[M, LargeObjectManager, Long] = primitive(_.createLO) @@ -326,6 +339,8 @@ class KleisliInterpreter[M[_]](logHandler: LogHandler[M])(implicit val asyncM: W override def onCancel[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): Kleisli[M, PGConnection, A] = outer.onCancel(this)(fa, fin) override def fromFuture[A](fut: PGConnectionIO[Future[A]]): Kleisli[M, PGConnection, A] = outer.fromFuture(this)(fut) override def fromFutureCancelable[A](fut: PGConnectionIO[(Future[A], PGConnectionIO[Unit])]): Kleisli[M, PGConnection, A] = outer.fromFutureCancelable(this)(fut) + override def cancelable[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): Kleisli[M, PGConnection, A] = outer.cancelable(this)(fa, fin) + // domain-specific operations are implemented in terms of `primitive` override def addDataType(a: String, b: Class[? <: org.postgresql.util.PGobject]) = primitive(_.addDataType(a, b)) diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/largeobject.scala b/modules/postgres/src/main/scala/doobie/postgres/free/largeobject.scala index 1250ac55f..65d459f9f 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/largeobject.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/largeobject.scala @@ -60,6 +60,7 @@ object largeobject { module => def onCancel[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): F[A] def fromFuture[A](fut: LargeObjectIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: LargeObjectIO[(Future[A], LargeObjectIO[Unit])]): F[A] + def cancelable[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // LargeObject @@ -130,6 +131,9 @@ object largeobject { module => case class FromFutureCancelable[A](fut: LargeObjectIO[(Future[A], LargeObjectIO[Unit])]) extends LargeObjectOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]) extends LargeObjectOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends LargeObjectOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -222,6 +226,7 @@ object largeobject { module => def onCancel[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]) = FF.liftF[LargeObjectOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: LargeObjectIO[Future[A]]) = FF.liftF[LargeObjectOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: LargeObjectIO[(Future[A], LargeObjectIO[Unit])]) = FF.liftF[LargeObjectOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]) = FF.liftF[LargeObjectOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[LargeObjectOp, Unit](PerformLogging(event)) // Smart constructors for LargeObject-specific operations. @@ -267,6 +272,7 @@ object largeobject { module => override def onCancel[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): LargeObjectIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: LargeObjectIO[Future[A]]): LargeObjectIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: LargeObjectIO[(Future[A], LargeObjectIO[Unit])]): LargeObjectIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: LargeObjectIO[A], fin: LargeObjectIO[Unit]): LargeObjectIO[A] = module.cancelable(fa, fin) } implicit def MonoidLargeObjectIO[A : Monoid]: Monoid[LargeObjectIO[A]] = new Monoid[LargeObjectIO[A]] { diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/largeobjectmanager.scala b/modules/postgres/src/main/scala/doobie/postgres/free/largeobjectmanager.scala index 53f09c272..6c625ec39 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/largeobjectmanager.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/largeobjectmanager.scala @@ -58,6 +58,7 @@ object largeobjectmanager { module => def onCancel[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): F[A] def fromFuture[A](fut: LargeObjectManagerIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: LargeObjectManagerIO[(Future[A], LargeObjectManagerIO[Unit])]): F[A] + def cancelable[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // LargeObjectManager @@ -117,6 +118,9 @@ object largeobjectmanager { module => case class FromFutureCancelable[A](fut: LargeObjectManagerIO[(Future[A], LargeObjectManagerIO[Unit])]) extends LargeObjectManagerOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]) extends LargeObjectManagerOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends LargeObjectManagerOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -176,6 +180,7 @@ object largeobjectmanager { module => def onCancel[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]) = FF.liftF[LargeObjectManagerOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: LargeObjectManagerIO[Future[A]]) = FF.liftF[LargeObjectManagerOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: LargeObjectManagerIO[(Future[A], LargeObjectManagerIO[Unit])]) = FF.liftF[LargeObjectManagerOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]) = FF.liftF[LargeObjectManagerOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[LargeObjectManagerOp, Unit](PerformLogging(event)) // Smart constructors for LargeObjectManager-specific operations. @@ -210,6 +215,7 @@ object largeobjectmanager { module => override def onCancel[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): LargeObjectManagerIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: LargeObjectManagerIO[Future[A]]): LargeObjectManagerIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: LargeObjectManagerIO[(Future[A], LargeObjectManagerIO[Unit])]): LargeObjectManagerIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: LargeObjectManagerIO[A], fin: LargeObjectManagerIO[Unit]): LargeObjectManagerIO[A] = module.cancelable(fa, fin) } implicit def MonoidLargeObjectManagerIO[A : Monoid]: Monoid[LargeObjectManagerIO[A]] = new Monoid[LargeObjectManagerIO[A]] { diff --git a/modules/postgres/src/main/scala/doobie/postgres/free/pgconnection.scala b/modules/postgres/src/main/scala/doobie/postgres/free/pgconnection.scala index 9edcd2b39..0ab6f2424 100644 --- a/modules/postgres/src/main/scala/doobie/postgres/free/pgconnection.scala +++ b/modules/postgres/src/main/scala/doobie/postgres/free/pgconnection.scala @@ -66,6 +66,7 @@ object pgconnection { module => def onCancel[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): F[A] def fromFuture[A](fut: PGConnectionIO[Future[A]]): F[A] def fromFutureCancelable[A](fut: PGConnectionIO[(Future[A], PGConnectionIO[Unit])]): F[A] + def cancelable[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): F[A] def performLogging(event: LogEvent): F[Unit] // PGConnection @@ -138,6 +139,9 @@ object pgconnection { module => case class FromFutureCancelable[A](fut: PGConnectionIO[(Future[A], PGConnectionIO[Unit])]) extends PGConnectionOp[A] { def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) } + case class Cancelable[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]) extends PGConnectionOp[A] { + def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + } case class PerformLogging(event: LogEvent) extends PGConnectionOp[Unit] { def visit[F[_]](v: Visitor[F]) = v.performLogging(event) } @@ -236,6 +240,7 @@ object pgconnection { module => def onCancel[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]) = FF.liftF[PGConnectionOp, A](OnCancel(fa, fin)) def fromFuture[A](fut: PGConnectionIO[Future[A]]) = FF.liftF[PGConnectionOp, A](FromFuture(fut)) def fromFutureCancelable[A](fut: PGConnectionIO[(Future[A], PGConnectionIO[Unit])]) = FF.liftF[PGConnectionOp, A](FromFutureCancelable(fut)) + def cancelable[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]) = FF.liftF[PGConnectionOp, A](Cancelable(fa, fin)) def performLogging(event: LogEvent) = FF.liftF[PGConnectionOp, Unit](PerformLogging(event)) // Smart constructors for PGConnection-specific operations. @@ -283,6 +288,7 @@ object pgconnection { module => override def onCancel[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): PGConnectionIO[A] = module.onCancel(fa, fin) override def fromFuture[A](fut: PGConnectionIO[Future[A]]): PGConnectionIO[A] = module.fromFuture(fut) override def fromFutureCancelable[A](fut: PGConnectionIO[(Future[A], PGConnectionIO[Unit])]): PGConnectionIO[A] = module.fromFutureCancelable(fut) + override def cancelable[A](fa: PGConnectionIO[A], fin: PGConnectionIO[Unit]): PGConnectionIO[A] = module.cancelable(fa, fin) } implicit def MonoidPGConnectionIO[A : Monoid]: Monoid[PGConnectionIO[A]] = new Monoid[PGConnectionIO[A]] { diff --git a/project/FreeGen2.scala b/project/FreeGen2.scala index b6e5ad013..c5546d7aa 100644 --- a/project/FreeGen2.scala +++ b/project/FreeGen2.scala @@ -301,6 +301,7 @@ class FreeGen2( | def onCancel[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): F[A] | def fromFuture[A](fut: ${ioname}[Future[A]]): F[A] | def fromFutureCancelable[A](fut: ${ioname}[(Future[A], ${ioname}[Unit])]): F[A] + | def cancelable[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): F[A] | def performLogging(event: LogEvent): F[Unit] | | // $sname @@ -351,6 +352,9 @@ class FreeGen2( | case class FromFutureCancelable[A](fut: ${ioname}[(Future[A], ${ioname}[Unit])]) extends ${opname}[A] { | def visit[F[_]](v: Visitor[F]) = v.fromFutureCancelable(fut) | } + | case class Cancelable[A](fa: ${ioname}[A], fin: ${ioname}[Unit]) extends ${opname}[A] { + | def visit[F[_]](v: Visitor[F]) = v.cancelable(fa, fin) + | } | case class PerformLogging(event: LogEvent) extends ${opname}[Unit] { | def visit[F[_]](v: Visitor[F]) = v.performLogging(event) | } @@ -381,6 +385,7 @@ class FreeGen2( | def onCancel[A](fa: ${ioname}[A], fin: ${ioname}[Unit]) = FF.liftF[${opname}, A](OnCancel(fa, fin)) | def fromFuture[A](fut: ${ioname}[Future[A]]) = FF.liftF[${opname}, A](FromFuture(fut)) | def fromFutureCancelable[A](fut: ${ioname}[(Future[A], ${ioname}[Unit])]) = FF.liftF[${opname}, A](FromFutureCancelable(fut)) + | def cancelable[A](fa: ${ioname}[A], fin: ${ioname}[Unit]) = FF.liftF[${opname}, A](Cancelable(fa, fin)) | def performLogging(event: LogEvent) = FF.liftF[${opname}, Unit](PerformLogging(event)) | | // Smart constructors for $oname-specific operations. @@ -406,6 +411,7 @@ class FreeGen2( | override def onCancel[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): ${ioname}[A] = module.onCancel(fa, fin) | override def fromFuture[A](fut: ${ioname}[Future[A]]): ${ioname}[A] = module.fromFuture(fut) | override def fromFutureCancelable[A](fut: ${ioname}[(Future[A], ${ioname}[Unit])]): ${ioname}[A] = module.fromFutureCancelable(fut) + | override def cancelable[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): ${ioname}[A] = module.cancelable(fa, fin) | } | | implicit def Monoid$ioname[A : Monoid]: Monoid[$ioname[A]] = new Monoid[$ioname[A]] { @@ -492,6 +498,8 @@ class FreeGen2( | override def onCancel[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): $klesA = outer.onCancel(this)(fa, fin) | override def fromFuture[A](fut: ${ioname}[Future[A]]): $klesA = outer.fromFuture(this)(fut) | override def fromFutureCancelable[A](fut: ${ioname}[(Future[A], ${ioname}[Unit])]): $klesA = outer.fromFutureCancelable(this)(fut) + | override def cancelable[A](fa: ${ioname}[A], fin: ${ioname}[Unit]): $klesA = outer.cancelable(this)(fa, fin) + | | | // domain-specific operations are implemented in terms of `primitive` |${ctors[A].map(_.kleisliImpl(sname)).mkString("\n")} @@ -594,6 +602,9 @@ class FreeGen2( | def fromFutureCancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fut: Free[G, (Future[A], Free[G, Unit])]): Kleisli[M, J, A] = Kleisli(j => | asyncM.fromFutureCancelable(fut.map { case (f, g) => (f, g.foldMap(interpreter).run(j)) }.foldMap(interpreter).run(j)) | ) + | def cancelable[G[_], J, A](interpreter: G ~> Kleisli[M, J, *])(fa: Free[G, A], fin: Free[G, Unit]): Kleisli[M, J, A] = Kleisli (j => + | asyncM.cancelable(fa.foldMap(interpreter).run(j), fin.foldMap(interpreter).run(j)) + | ) | def embed[J, A](e: Embedded[A]): Kleisli[M, J, A] = | e match { | $kleisliInterpreterEmbedMatch