Skip to content
Merged
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ Check the backward compatibility information on those libraries to check which v
| 1.3.0 | 1.0.5 | 0.9.4 | 2.6.10 |
| 2.0.0 | 1.0.5 | 0.12.1 | 2.6.10 |
| 2.1.0 | 1.0.9 | 0.13.4 | 2.6.10 |
| master | 1.0.9 | 0.13.4 | 2.6.10 |
| 3.0.0 | 1.0.11 | 1.0.0 | 2.6.10 |
| master | 1.0.11 | 1.0.0 | 2.6.10 |



Expand Down Expand Up @@ -355,15 +356,16 @@ import doobie.implicits._
import io.github.gaelrenoux.tranzactio.DbException
import io.github.gaelrenoux.tranzactio.doobie._
import zio.blocking.Blocking
import zio.clock.Clock

val liveQuery: ZIO[Connection, DbException, List[String]] = tzio { sql"SELECT name FROM users".query[String].to[List] }
val testQuery: ZIO[Connection, DbException, List[String]] = ZIO.succeed(List("Buffy Summers"))

val liveEffect: ZIO[Database, DbException, List[String]] = Database.transactionOrWiden(liveQuery)
val testEffect: ZIO[Database, DbException, List[String]] = Database.transactionOrWiden(testQuery)

val willFail: ZIO[Blocking, Any, List[String]] = liveEffect.provideLayer(Database.none) // THIS WILL FAIL
val testing: ZIO[Blocking, Any, List[String]] = testEffect.provideLayer(Database.none) // This will work
val willFail: ZIO[Blocking with Clock, Any, List[String]] = liveEffect.provideLayer(Database.none) // THIS WILL FAIL
val testing: ZIO[Blocking with Clock, Any, List[String]] = testEffect.provideLayer(Database.none) // This will work
```


Expand Down
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ scalacOptions ++= allVersionsOption ++ {
}


val ZioVersion = "1.0.9"
val ZioCatsVersion = "2.5.1.0"
val DoobieVersion = "0.13.4"
val ZioVersion = "1.0.11"
val ZioCatsVersion = "3.1.1.0"
val DoobieVersion = "1.0.0-RC1"
val AnormVersion = "2.6.10"
val H2Version = "1.4.200"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,21 @@ object ConnectionSource {
*
* When a Database method is called with no available implicit ErrorStrategiesRef, the default ErrorStrategiesRef will
* be used. */
val fromDatasource: ZLayer[Has[DataSource] with Blocking with Clock, Nothing, ConnectionSource] =
val fromDatasource: ZLayer[Has[DataSource] with TranzactioEnv, Nothing, ConnectionSource] =
fromDatasource(ErrorStrategies.Parent)

/** As `fromDatasource`, but provides a default ErrorStrategiesRef.
*
* When a Database method is called with no available implicit ErrorStrategiesRef, the ErrorStrategiesRef in argument
* will be used. */
def fromDatasource(errorStrategies: ErrorStrategiesRef): ZLayer[Has[DataSource] with Blocking with Clock, Nothing, ConnectionSource] =
ZIO.access[Has[DataSource] with Blocking with Clock] { env =>
def fromDatasource(errorStrategies: ErrorStrategiesRef): ZLayer[Has[DataSource] with TranzactioEnv, Nothing, ConnectionSource] =
ZIO.access[Has[DataSource] with TranzactioEnv] { env =>
new DatasourceService(env, errorStrategies)
}.toLayer

/** As `fromDatasource(ErrorStrategiesRef)`, but an `ErrorStrategies` is provided through a layer instead of as a parameter. */
val fromDatasourceAndErrorStrategies: ZLayer[Has[DataSource] with Has[ErrorStrategies] with Blocking with Clock, Nothing, ConnectionSource] =
ZIO.access[Has[DataSource] with Has[ErrorStrategies] with Blocking with Clock] { env =>
val fromDatasourceAndErrorStrategies: ZLayer[Has[DataSource] with Has[ErrorStrategies] with TranzactioEnv, Nothing, ConnectionSource] =
ZIO.access[Has[DataSource] with Has[ErrorStrategies] with TranzactioEnv] { env =>
val errorStrategies = env.get[ErrorStrategies]
new DatasourceService(env, errorStrategies)
}.toLayer
Expand All @@ -164,8 +164,8 @@ object ConnectionSource {
*
* When a Database method is called with no available implicit ErrorStrategiesRef, the ErrorStrategiesRef in argument
* will be used. */
def fromConnection(errorStrategiesRef: ErrorStrategiesRef): ZLayer[Has[Connection] with Blocking with Clock, Nothing, ConnectionSource] =
ZIO.accessM[Has[Connection] with Blocking with Clock] { env =>
def fromConnection(errorStrategiesRef: ErrorStrategiesRef): ZLayer[Has[Connection] with TranzactioEnv, Nothing, ConnectionSource] =
ZIO.accessM[Has[Connection] with TranzactioEnv] { env =>
val connection = env.get[Connection]
Semaphore.make(1).map {
new SingleConnectionService(connection, _, env, errorStrategiesRef)
Expand Down
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 TranzactioEnv, 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: TranzactioEnv, 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
final val fromDatasource: ZLayer[Has[DataSource] with TranzactioEnv, Nothing, Database] =
(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
Expand Up @@ -31,12 +31,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: TranzactioEnv, 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 TranzactioEnv, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with TranzactioEnv =>
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
26 changes: 13 additions & 13 deletions src/main/scala/io/github/gaelrenoux/tranzactio/doobie/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ import _root_.doobie.free.KleisliInterpreter
import _root_.doobie.util.transactor.{Strategy, Transactor}
import cats.effect.Resource
import io.github.gaelrenoux.tranzactio.test.DatabaseModuleTestOps
import io.github.gaelrenoux.tranzactio.utils.ZCatsBlocker
import zio.blocking.Blocking
import zio.interop.catz._
import zio.stream.ZStream
import zio.stream.interop.fs2z._
import zio.{Has, Tag, Task, ZIO, ZLayer}

import java.sql.{Connection => JdbcConnection}


/** TranzactIO module for Doobie. */
package object doobie extends Wrapper {
override final type Connection = Has[Transactor[Task]]
Expand All @@ -35,7 +32,7 @@ package object doobie extends Wrapper {
/** Converts a Doobie stream to a ZStream. Note that you can provide a queue size, default value is the same as in ZIO. */
final def tzioStream[A](q: fs2.Stream[Query, A], queueSize: Int = DefaultStreamQueueSize): TranzactIOStream[A] =
ZStream.accessStream[Connection] { c =>
c.get.transP(monadErrorInstance).apply(q).toZStream(queueSize)
c.get.transP.apply(q).toZStream(queueSize)
}.mapError(DbException.Wrapped)

/** Database for the Doobie wrapper */
Expand All @@ -47,17 +44,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] =
ZCatsBlocker.provide(env).map { b =>
val connect = (c: JdbcConnection) => Resource.pure[Task, JdbcConnection](c)
val interp = KleisliInterpreter[Task](b).ConnectionInterpreter
val tran = Transactor(connection, connect, interp, Strategy.void)
Has(tran)
}
final def connectionFromJdbc(env: TranzactioEnv, connection: JdbcConnection): ZIO[Any, Nothing, Connection] = {
ZIO.runtime[TranzactioEnv].flatMap { implicit r: zio.Runtime[TranzactioEnv] =>
ZIO.succeed[Connection] {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hmemcpy I'm using succeed instead of effectTotal here, because I don't think there's any effecting code going under the hood here. Am I missing something ?

val connect = (c: JdbcConnection) => Resource.pure[Task, JdbcConnection](c)
val interp = KleisliInterpreter[Task].ConnectionInterpreter
val tran = Transactor(connection, connect, interp, Strategy.void)
Has(tran)
}
}.provide(env)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PawelJ-PL In your code, you used provideLayer, I think we can just use provide here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I can't remember, what I used provideLayer 😄

}

/** 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 TranzactioEnv, Nothing, Database] =
ZLayer.fromFunction { env: ConnectionSource with TranzactioEnv =>
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
4 changes: 4 additions & 0 deletions src/main/scala/io/github/gaelrenoux/tranzactio/package.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package io.github.gaelrenoux

import zio.Has
import zio.blocking.Blocking
import zio.clock.Clock

package object tranzactio {

type ConnectionSource = Has[ConnectionSource.Service]

type TranzactioEnv = Blocking with Clock

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.gaelrenoux.tranzactio.test

import io.github.gaelrenoux.tranzactio.{DatabaseModuleBase, DatabaseOps, DbException, ErrorStrategiesRef}
import zio.blocking.Blocking
import io.github.gaelrenoux.tranzactio._
import zio.{Has, Tag, ZIO, ZLayer}

/** Testing utilities on the Database module. */
Expand All @@ -11,11 +10,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: TranzactioEnv): 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[TranzactioEnv, Nothing, Database] = ZLayer.fromFunction { b: TranzactioEnv =>
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
13 changes: 0 additions & 13 deletions src/main/scala/io/github/gaelrenoux/tranzactio/utils/package.scala

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package io.github.gaelrenoux.tranzactio.integration

import anorm._
import io.github.gaelrenoux.tranzactio.ConnectionSource
import io.github.gaelrenoux.tranzactio.anorm._
import io.github.gaelrenoux.tranzactio.{ConnectionSource, TranzactioEnv}
import samples.Person
import samples.anorm.PersonQueries
import zio.blocking.Blocking
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 TranzactioEnv, 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 @@ -2,11 +2,10 @@ package io.github.gaelrenoux.tranzactio.integration

import doobie.implicits._
import doobie.util.fragment.Fragment
import io.github.gaelrenoux.tranzactio.ConnectionSource
import io.github.gaelrenoux.tranzactio.doobie._
import io.github.gaelrenoux.tranzactio.{ConnectionSource, TranzactioEnv}
import samples.Person
import samples.doobie.PersonQueries
import zio.blocking.Blocking
import zio.test.Assertion._
import zio.test._
import zio.{ULayer, ZLayer}
Expand All @@ -15,7 +14,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 TranzactioEnv, Nothing, Database] = Database.fromConnectionSource

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

Expand Down