Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,27 @@ abstract class DatabaseModuleBase[Connection, Dbs <: DatabaseOps.ServiceOps[Conn
}

/** Creates a Database Layer which requires an existing ConnectionSource. */
def fromConnectionSource: ZLayer[ConnectionSource with Blocking, Nothing, Database]
def fromConnectionSource: ZLayer[ConnectionSource with Blocking with Clock, Nothing, Database]

/** Creates a Tranzactio Connection, given a JDBC connection and a Blocking. Useful for some utilities. */
def connectionFromJdbc(env: Blocking, connection: JdbcConnection): ZIO[Any, Nothing, Connection]
def connectionFromJdbc(env: Blocking with Clock, connection: JdbcConnection): ZIO[Any, Nothing, Connection]

/** Commodity method: creates a Database Layer which includes its own ConnectionSource based on a DataSource. Most
* connection pool implementations should be able to provide you a DataSource.
*
* When no implicit ErrorStrategies is available, the default ErrorStrategies will be used.
*/
final val fromDatasource: ZLayer[Has[DataSource] with Blocking with Clock, Nothing, Database] =
(ConnectionSource.fromDatasource ++ Blocking.any) >>> fromConnectionSource
(ConnectionSource.fromDatasource ++ Blocking.any ++ Clock.any) >>> fromConnectionSource

/** As `fromDatasource`, but provides a default ErrorStrategiesRef. When a method is called with no available implicit
* ErrorStrategiesRef, the ErrorStrategiesRef in argument will be used. */
final def fromDatasource(errorStrategies: ErrorStrategiesRef): ZLayer[Has[DataSource] with Blocking with Clock, Nothing, Database] =
(ConnectionSource.fromDatasource(errorStrategies) ++ Blocking.any) >>> fromConnectionSource
(ConnectionSource.fromDatasource(errorStrategies) ++ Blocking.any ++ Clock.any) >>> fromConnectionSource

/** As `fromDatasource(ErrorStrategiesRef)`, but an `ErrorStrategies` is provided through a layer instead of as a parameter. */
final val fromDatasourceAndErrorStrategies: ZLayer[Has[DataSource] with Has[ErrorStrategies] with Blocking with Clock, Nothing, Database] =
(ConnectionSource.fromDatasourceAndErrorStrategies ++ Blocking.any) >>> fromConnectionSource
(ConnectionSource.fromDatasourceAndErrorStrategies ++ Blocking.any ++ Clock.any) >>> fromConnectionSource


val any: ZLayer[Database, Nothing, Database] = ZLayer.requires[Database]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.github.gaelrenoux.tranzactio

import java.sql.{Connection => JdbcConnection}

import io.github.gaelrenoux.tranzactio.test.DatabaseModuleTestOps
import izumi.reflect.Tag
import zio.blocking.{Blocking, effectBlocking}
import zio.clock.Clock
import zio.{Has, ZIO, ZLayer}


Expand Down Expand Up @@ -32,12 +32,12 @@ package object anorm extends Wrapper {
private[tranzactio] override implicit val connectionTag: Tag[Connection] = anorm.connectionTag

/** How to provide a Connection for the module, given a JDBC connection and some environment. */
final def connectionFromJdbc(env: Blocking, connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
final def connectionFromJdbc(env: Blocking with Clock, connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
ZIO.succeed(Has(connection) ++ env)

/** Creates a Database Layer which requires an existing ConnectionSource. */
final def fromConnectionSource: ZLayer[ConnectionSource with Blocking, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with Blocking =>
final def fromConnectionSource: ZLayer[ConnectionSource with Blocking with Clock, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with Blocking with Clock =>
new DatabaseServiceBase[Connection](env.get[ConnectionSource.Service]) with Database.Service {
override final def connectionFromJdbc(connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
self.connectionFromJdbc(env, connection)
Expand Down
23 changes: 13 additions & 10 deletions src/main/scala/io/github/gaelrenoux/tranzactio/doobie/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import cats.effect.Resource
import io.github.gaelrenoux.tranzactio.test.DatabaseModuleTestOps
import izumi.reflect.Tag
import zio.blocking.Blocking
import zio.clock.Clock
import zio.interop.catz._
import zio.interop.catz.implicits.rts
import zio.stream.ZStream
import zio.stream.interop.fs2z._
import zio.{Has, Task, ZIO, ZLayer}
Expand Down Expand Up @@ -47,17 +47,20 @@ package object doobie extends Wrapper {
private[tranzactio] override implicit val connectionTag: Tag[Connection] = doobie.connectionTag

/** How to provide a Connection for the module, given a JDBC connection and some environment. */
final def connectionFromJdbc(env: Blocking, connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
ZIO.effectTotal {
val connect = (c: JdbcConnection) => Resource.pure[Task, JdbcConnection](c)
val interp = KleisliInterpreter[Task].ConnectionInterpreter
val tran = Transactor(connection, connect, interp, Strategy.void)
Has(tran)
}
final def connectionFromJdbc(env: Blocking with Clock, connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
ZIO.runtime[Blocking with Clock].flatMap{implicit r: zio.Runtime[Blocking with Clock] => {
ZIO.effectTotal[Connection] {
val connect = (c: JdbcConnection) => Resource.pure[Task, JdbcConnection](c)
val interp = KleisliInterpreter[Task].ConnectionInterpreter
val tran = Transactor(connection, connect, interp, Strategy.void)
Has(tran)
}
}}
.provideLayer(ZLayer.succeed(env.get[Blocking.Service]) ++ ZLayer.succeed(env.get[Clock.Service]))

/** Creates a Database Layer which requires an existing ConnectionSource. */
final def fromConnectionSource: ZLayer[ConnectionSource with Blocking, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with Blocking =>
final def fromConnectionSource: ZLayer[ConnectionSource with Blocking with Clock, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with Blocking with Clock =>
new DatabaseServiceBase[Connection](env.get[ConnectionSource.Service]) with Database.Service {
override final def connectionFromJdbc(connection: JdbcConnection): ZIO[Any, Nothing, Connection] =
self.connectionFromJdbc(env, connection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.gaelrenoux.tranzactio.test
import io.github.gaelrenoux.tranzactio.{DatabaseModuleBase, DatabaseOps, DbException, ErrorStrategiesRef}
import izumi.reflect.Tag
import zio.blocking.Blocking
import zio.clock.Clock
import zio.{Has, ZIO, ZLayer}

/** Testing utilities on the Database module. */
Expand All @@ -12,11 +13,11 @@ trait DatabaseModuleTestOps[Connection <: Has[_]] extends DatabaseModuleBase[Con

/** A Connection which is incapable of running anything, to use when unit testing (and the queries are actually stubbed,
* so they do not need a Database). Trying to run actual queries against it will fail. */
def noConnection(env: Blocking): ZIO[Any, Nothing, Connection] = connectionFromJdbc(env, NoopJdbcConnection)
def noConnection(env: Blocking with Clock): ZIO[Any, Nothing, Connection] = connectionFromJdbc(env, NoopJdbcConnection)

/** A Database which is incapable of running anything, to use when unit testing (and the queries are actually stubbed,
* so they do not need a Database). Trying to run actual queries against it will fail. */
lazy val none: ZLayer[Blocking, Nothing, Database] = ZLayer.fromFunction { b: Blocking =>
lazy val none: ZLayer[Blocking with Clock, Nothing, Database] = ZLayer.fromFunction { b: Blocking with Clock =>
new Service {
override def transactionR[R <: Has[_], E, A](zio: ZIO[Connection with R, E, A], commitOnFailure: Boolean)
(implicit errorStrategies: ErrorStrategiesRef): ZIO[R, Either[DbException, E], A] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import io.github.gaelrenoux.tranzactio.anorm._
import samples.Person
import samples.anorm.PersonQueries
import zio.blocking.Blocking
import zio.clock.Clock
import zio.test.Assertion._
import zio.test._
import zio.{ULayer, ZLayer}

/** Integration tests for Doobie */
object AnormIT extends ITSpec[Database, PersonQueries] {

override val dbLayer: ZLayer[ConnectionSource with Blocking, Nothing, Database] = Database.fromConnectionSource
override val dbLayer: ZLayer[ConnectionSource with Blocking with Clock, Nothing, Database] = Database.fromConnectionSource

override val personQueriesLive: ULayer[PersonQueries] = PersonQueries.live

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.github.gaelrenoux.tranzactio.doobie._
import samples.Person
import samples.doobie.PersonQueries
import zio.blocking.Blocking
import zio.clock.Clock
import zio.test.Assertion._
import zio.test._
import zio.{ULayer, ZLayer}
Expand All @@ -15,7 +16,7 @@ import zio.{ULayer, ZLayer}
/** Integration tests for Doobie */
object DoobieIT extends ITSpec[Database, PersonQueries] {

override val dbLayer: ZLayer[ConnectionSource with Blocking, Nothing, Database] = Database.fromConnectionSource
override val dbLayer: ZLayer[ConnectionSource with Blocking with Clock, Nothing, Database] = Database.fromConnectionSource

override val personQueriesLive: ULayer[PersonQueries] = PersonQueries.live

Expand Down