Skip to content

Commit 3bd0def

Browse files
committed
Abstracting runner over Async type + creating the future module
1 parent 9fc2b2a commit 3bd0def

File tree

16 files changed

+160
-106
lines changed

16 files changed

+160
-106
lines changed

core/src/main/scala/core/database/ComposeWithCompletion.scala

Lines changed: 0 additions & 47 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.zengularity.querymonad.core.database
2+
3+
// import scala.concurrent.{ExecutionContext, Future}
4+
import scala.language.higherKinds
5+
6+
/**
7+
* Heavily inspired from work done by @cchantep in Acolyte (see acolyte.reactivemongo.ComposeWithCompletion)
8+
*/
9+
trait LiftAsync[F[_], M[_], A] {
10+
type Outer
11+
12+
def apply[Resource](
13+
loaner: WithResource[F, Resource],
14+
f: Resource => M[A]
15+
): F[Outer]
16+
}
17+
18+
object LiftAsync {
19+
20+
type Aux[F[_], M[_], A, B] = LiftAsync[F, M, A] { type Outer = B }
21+
22+
}
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
11
package com.zengularity.querymonad.core.database
22

3-
import scala.concurrent.Future
43
import scala.language.higherKinds
54

65
/**
76
* A class who can run a Query.
87
*/
9-
sealed trait QueryRunner[Resource] {
8+
sealed trait QueryRunner[F[_], Resource] {
109
def apply[M[_], T](query: QueryT[M, Resource, T])(
11-
implicit compose: ComposeWithCompletion[M, T]
12-
): Future[compose.Outer]
10+
implicit lift: LiftAsync[F, M, T]
11+
): F[lift.Outer]
1312
}
1413

1514
object QueryRunner {
16-
private class DefaultRunner[Resource](wr: WithResource[Resource])
17-
extends QueryRunner[Resource] {
15+
private class DefaultRunner[F[_], Resource](wr: WithResource[F, Resource])
16+
extends QueryRunner[F, Resource] {
1817
def apply[M[_], T](
1918
query: QueryT[M, Resource, T]
20-
)(implicit compose: ComposeWithCompletion[M, T]): Future[compose.Outer] =
21-
compose(wr, query.run)
19+
)(implicit lift: LiftAsync[F, M, T]): F[lift.Outer] =
20+
lift(wr, query.run)
2221
}
2322

2423
// Default factory
25-
def apply[Resource](
26-
wr: WithResource[Resource]
27-
): QueryRunner[Resource] =
24+
def apply[F[_], Resource](
25+
wr: WithResource[F, Resource]
26+
): QueryRunner[F, Resource] =
2827
new DefaultRunner(wr)
2928
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.zengularity.querymonad.core.database
22

3-
import scala.concurrent.Future
3+
// import scala.concurrent.Future
4+
import scala.language.higherKinds
45

5-
trait WithResource[Resource] {
6-
def apply[A](f: Resource => Future[A]): Future[A]
6+
trait WithResource[F[_], Resource] {
7+
def apply[A](f: Resource => F[A]): F[A]
78
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.zengularity.querymonad.module.future
2+
3+
import scala.concurrent.{ExecutionContext, Future}
4+
import scala.language.higherKinds
5+
6+
import com.zengularity.querymonad.core.database.LiftAsync
7+
8+
trait LiftAsyncFuture extends LowPriority {
9+
10+
implicit def futureOut[A]: LiftAsync.Aux[Future, Future, A, A] =
11+
new LiftAsync[Future, Future, A] {
12+
type Outer = A
13+
14+
def apply[In](
15+
loaner: WithResourceF[In],
16+
f: In => Future[A]
17+
): Future[Outer] = loaner(f)
18+
19+
override val toString = "futureOut"
20+
}
21+
22+
}
23+
24+
trait LowPriority { _: LiftAsyncFuture =>
25+
26+
implicit def pureOut[F[_], A](
27+
implicit ec: ExecutionContext
28+
): LiftAsync.Aux[Future, F, A, F[A]] =
29+
new LiftAsync[Future, F, A] {
30+
type Outer = F[A]
31+
32+
def apply[In](loaner: WithResourceF[In], f: In => F[A]): Future[Outer] =
33+
loaner(r => Future(f(r)))
34+
35+
override val toString = "pureOut"
36+
}
37+
38+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.zengularity.querymonad.module
2+
3+
import scala.concurrent.Future
4+
5+
import com.zengularity.querymonad.core.database.{QueryRunner, WithResource}
6+
7+
package object future {
8+
9+
type WithResourceF[Resource] = WithResource[Future, Resource]
10+
11+
type QueryRunnerF[Resource] = QueryRunner[Future, Resource]
12+
13+
object QueryRunnerF {
14+
def apply[Resource](wc: WithResourceF[Resource]): QueryRunnerF[Resource] =
15+
QueryRunnerF[Resource](wc)
16+
}
17+
18+
object implicits extends LiftAsyncFuture
19+
20+
}

core/src/main/scala/module/sql/package.scala

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.zengularity.querymonad.module
22

33
import java.sql.Connection
44

5-
// import scala.concurrent.ExecutionContext
65
import scala.language.higherKinds
6+
import scala.concurrent.Future
77

88
import cats.Applicative
99

@@ -60,13 +60,24 @@ package object sql {
6060
type SqlQueryE[A, Err] = QueryE[Connection, A, Err]
6161

6262
// Query runner aliases
63-
type WithSqlConnection = WithResource[Connection]
63+
type WithSqlConnection[F[_]] = WithResource[F, Connection]
6464

65-
type SqlQueryRunner = QueryRunner[Connection]
65+
type SqlQueryRunner[F[_]] = QueryRunner[F, Connection]
6666

6767
object SqlQueryRunner {
68-
def apply(wc: WithSqlConnection): SqlQueryRunner =
69-
QueryRunner[Connection](wc)
68+
def apply[F[_]](wc: WithSqlConnection[F]): SqlQueryRunner[F] =
69+
QueryRunner[F, Connection](wc)
70+
}
71+
72+
object future {
73+
type WithSqlConnectionF = WithSqlConnection[Future]
74+
75+
type SqlQueryRunnerF = SqlQueryRunner[Future]
76+
77+
object SqlQueryRunnerF {
78+
def apply(wc: WithSqlConnectionF): SqlQueryRunnerF =
79+
SqlQueryRunner(wc)
80+
}
7081
}
7182

7283
}

core/src/test/scala/module/sql/SqlQueryRunnerSpec.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import org.specs2.mutable.Specification
1212
import com.zengularity.querymonad.module.sql.{
1313
SqlQuery,
1414
SqlQueryRunner,
15-
SqlQueryT,
16-
WithSqlConnection
15+
SqlQueryT
1716
}
17+
import com.zengularity.querymonad.module.future.implicits._
18+
import com.zengularity.querymonad.module.sql.future.WithSqlConnectionF
1819
import com.zengularity.querymonad.test.module.sql.models.{Material, Professor}
1920
import com.zengularity.querymonad.test.module.sql.utils.SqlConnectionFactory
2021

@@ -23,7 +24,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
2324
"SqlQueryRunner" should {
2425
// execute lift Queries
2526
"return integer value lift in Query using pure" in {
26-
val withSqlConnection: WithSqlConnection =
27+
val withSqlConnection: WithSqlConnectionF =
2728
SqlConnectionFactory.withSqlConnection(AcolyteQueryResult.Nil)
2829
val runner = SqlQueryRunner(withSqlConnection)
2930
val query = SqlQuery.pure(1)
@@ -32,7 +33,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
3233
}
3334

3435
"return optional value lift in Query using liftF" in {
35-
val withSqlConnection: WithSqlConnection =
36+
val withSqlConnection: WithSqlConnectionF =
3637
SqlConnectionFactory.withSqlConnection(AcolyteQueryResult.Nil)
3738
val runner = SqlQueryRunner(withSqlConnection)
3839
val query = SqlQueryT.liftF(Seq(1))
@@ -42,7 +43,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
4243

4344
// execute single query
4445
"retrieve professor with id 1" in {
45-
val withSqlConnection: WithSqlConnection =
46+
val withSqlConnection: WithSqlConnectionF =
4647
SqlConnectionFactory.withSqlConnection(Professor.resultSet)
4748
val runner = SqlQueryRunner(withSqlConnection)
4849
val result = runner(Professor.fetchProfessor(1)).map(_.get)
@@ -53,7 +54,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
5354
}
5455

5556
"retrieve material with id 1" in {
56-
val withSqlConnection: WithSqlConnection =
57+
val withSqlConnection: WithSqlConnectionF =
5758
SqlConnectionFactory.withSqlConnection(Material.resultSet)
5859
val runner = SqlQueryRunner(withSqlConnection)
5960
val result = runner(Material.fetchMaterial(1)).map(_.get)
@@ -64,7 +65,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
6465
}
6566

6667
"not retrieve professor with id 2" in {
67-
val withSqlConnection: WithSqlConnection =
68+
val withSqlConnection: WithSqlConnectionF =
6869
SqlConnectionFactory.withSqlConnection(AcolyteQueryResult.Nil)
6970
val runner = SqlQueryRunner(withSqlConnection)
7071
val query = for {
@@ -87,7 +88,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
8788
case _ =>
8889
AcolyteQueryResult.Nil
8990
}
90-
val withSqlConnection: WithSqlConnection =
91+
val withSqlConnection: WithSqlConnectionF =
9192
SqlConnectionFactory.withSqlConnection(handler)
9293
val runner = SqlQueryRunner(withSqlConnection)
9394
val query = for {
@@ -109,7 +110,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
109110
case _ =>
110111
AcolyteQueryResult.Nil
111112
}
112-
val withSqlConnection: WithSqlConnection =
113+
val withSqlConnection: WithSqlConnectionF =
113114
SqlConnectionFactory.withSqlConnection(handler)
114115
val runner = SqlQueryRunner(withSqlConnection)
115116
val query = for {
@@ -132,7 +133,7 @@ class SqlQueryRunnerSpec(implicit ee: ExecutionEnv) extends Specification {
132133

133134
val queryResult: AcolyteQueryResult =
134135
(RowLists.rowList1(classOf[Int] -> "res").append(5))
135-
val withSqlConnection: WithSqlConnection =
136+
val withSqlConnection: WithSqlConnectionF =
136137
SqlConnectionFactory.withSqlConnection(queryResult)
137138
val runner = SqlQueryRunner(withSqlConnection)
138139
val query =

core/src/test/scala/module/sql/utils/SqlConnectionFactory.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ import acolyte.jdbc.{
1111
ScalaCompositeHandler
1212
}
1313

14-
import com.zengularity.querymonad.module.sql.WithSqlConnection
14+
import com.zengularity.querymonad.module.sql.future.WithSqlConnectionF
1515

1616
object SqlConnectionFactory {
1717

1818
def withSqlConnection[A <: AcolyteQueryResult](
1919
resultsSet: A
20-
): WithSqlConnection =
21-
new WithSqlConnection {
20+
): WithSqlConnectionF =
21+
new WithSqlConnectionF {
2222
def apply[B](f: Connection => Future[B]): Future[B] =
2323
AcolyteDSL.withQueryResult(resultsSet) { connection =>
2424
f(connection).andThen { case _ => connection.close() }
2525
}
2626

2727
}
2828

29-
def withSqlConnection(handler: ScalaCompositeHandler): WithSqlConnection =
30-
new WithSqlConnection {
29+
def withSqlConnection(handler: ScalaCompositeHandler): WithSqlConnectionF =
30+
new WithSqlConnectionF {
3131
def apply[B](f: Connection => Future[B]): Future[B] = {
3232
val con = AcolyteDSL.connection(handler)
3333
f(con).andThen { case _ => con.close() }

examples/sample-app/app/wiring/AppLoader.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.zengularity.querymonad.module.sql.{
1515
SqlQueryRunner,
1616
SqlQueryT
1717
}
18+
import com.zengularity.querymonad.module.future.implicits._
1819
import com.zengularity.querymonad.module.playsql.database.WithPlayTransaction
1920

2021
class AppComponents(context: Context)

0 commit comments

Comments
 (0)