Skip to content

Commit

Permalink
Query' altered execution: Allow changing result type
Browse files Browse the repository at this point in the history
  • Loading branch information
jatcwang committed Feb 22, 2025
1 parent d685883 commit 9342af0
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 54 deletions.
97 changes: 49 additions & 48 deletions modules/core/src/main/scala/doobie/util/query.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ object query {

/** Just like `to` but allowing to alter `PreparedExecution`.
*/
def toAlteringExecution[F[_]](
def toAlteringExecution[F[_], R](
a: A,
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]] = {
fn: PreparedExecution[F[B]] => PreparedExecution[R]
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[R] = {
toConnectionIOAlteringExecution(a, IHRS.build[F, B], fn)
}

Expand All @@ -124,13 +124,13 @@ object query {

/** Just like `toMap` but allowing to alter `PreparedExecution`.
*/
def toMapAlteringExecution[K, V](
def toMapAlteringExecution[K, V, R](
a: A,
fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]]
fn: PreparedExecution[Map[K, V]] => PreparedExecution[R]
)(implicit
ev: B =:= (K, V),
f: FactoryCompat[(K, V), Map[K, V]]
): ConnectionIO[Map[K, V]] =
): ConnectionIO[R] =
toConnectionIOAlteringExecution(a, IHRS.buildPair[Map, K, V](f, read.map(ev)), fn)

/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
Expand All @@ -142,10 +142,10 @@ object query {

/** Just like `accumulate` but allowing to alter `PreparedExecution`.
*/
def accumulateAlteringExecution[F[_]: Alternative](
def accumulateAlteringExecution[F[_]: Alternative, R](
a: A,
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
): ConnectionIO[F[B]] =
fn: PreparedExecution[F[B]] => PreparedExecution[R]
): ConnectionIO[R] =
toConnectionIOAlteringExecution(a, IHRS.accumulate[F, B], fn)

/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
Expand All @@ -157,7 +157,7 @@ object query {

/** Just like `unique` but allowing to alter `PreparedExecution`.
*/
def uniqueAlteringExecution(a: A, fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B] =
def uniqueAlteringExecution[R](a: A, fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R] =
toConnectionIOAlteringExecution(a, IHRS.getUnique[B], fn)

/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
Expand All @@ -169,10 +169,10 @@ object query {

/** Just like `option` but allowing to alter `PreparedExecution`.
*/
def optionAlteringExecution(
def optionAlteringExecution[R](
a: A,
fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]]
): ConnectionIO[Option[B]] =
fn: PreparedExecution[Option[B]] => PreparedExecution[R]
): ConnectionIO[R] =
toConnectionIOAlteringExecution(a, IHRS.getOption[B], fn)

/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
Expand All @@ -185,20 +185,20 @@ object query {

/** Just like `nel` but allowing to alter `PreparedExecution`.
*/
def nelAlteringExecution(
def nelAlteringExecution[R](
a: A,
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
): ConnectionIO[NonEmptyList[B]] =
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
): ConnectionIO[R] =
toConnectionIOAlteringExecution(a, IHRS.nel[B], fn)

private def toConnectionIO[C](a: A, rsio: ResultSetIO[C]): ConnectionIO[C] =
IHC.executeWithResultSet(preparedExecution(sql, a, rsio), mkLoggingInfo(a))

private def toConnectionIOAlteringExecution[C](
private def toConnectionIOAlteringExecution[C, R](
a: A,
rsio: ResultSetIO[C],
fn: PreparedExecution[C] => PreparedExecution[C]
): ConnectionIO[C] =
fn: PreparedExecution[C] => PreparedExecution[R]
): ConnectionIO[R] =
IHC.executeWithResultSet(fn(preparedExecution(sql, a, rsio)), mkLoggingInfo(a))

private def preparedExecution[C](sql: String, a: A, rsio: ResultSetIO[C]): PreparedExecution[C] =
Expand Down Expand Up @@ -248,34 +248,35 @@ object query {
override def outputAnalysis: ConnectionIO[Analysis] = outer.outputAnalysis
override def streamWithChunkSize(n: Int): Stream[ConnectionIO, B] = outer.streamWithChunkSize(a, n)
override def accumulate[F[_]: Alternative]: ConnectionIO[F[B]] = outer.accumulate[F](a)
override def accumulateAlteringExecution[F[_]: Alternative](
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
): ConnectionIO[F[B]] = outer.accumulateAlteringExecution(a, fn)
override def accumulateAlteringExecution[F[_]: Alternative, R](
fn: PreparedExecution[F[B]] => PreparedExecution[R]
): ConnectionIO[R] = outer.accumulateAlteringExecution(a, fn)
override def to[F[_]](implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]] = outer.to[F](a)
override def toAlteringExecution[F[_]](fn: PreparedExecution[F[B]] => PreparedExecution[F[B]])(implicit
override def toAlteringExecution[F[_], R](fn: PreparedExecution[F[B]] => PreparedExecution[R])(implicit
f: FactoryCompat[B, F[B]]
): ConnectionIO[F[B]] =
): ConnectionIO[R] =
outer.toAlteringExecution(a, fn)
override def toMap[K, V](implicit
ev: B =:= (K, V),
f: FactoryCompat[(K, V), Map[K, V]]
): ConnectionIO[Map[K, V]] = outer.toMap(a)
override def toMapAlteringExecution[K, V](fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]])(

override def toMapAlteringExecution[K, V, R](fn: PreparedExecution[Map[K, V]] => PreparedExecution[R])(
implicit
ev: B =:= (K, V),
f: FactoryCompat[(K, V), Map[K, V]]
): ConnectionIO[Map[K, V]] = outer.toMapAlteringExecution(a, fn)
): ConnectionIO[R] = outer.toMapAlteringExecution(a, fn)
override def unique: ConnectionIO[B] = outer.unique(a)
override def uniqueAlteringExecution(fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B] =
override def uniqueAlteringExecution[R](fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R] =
outer.uniqueAlteringExecution(a, fn)
override def option: ConnectionIO[Option[B]] = outer.option(a)
override def optionAlteringExecution(fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]])
: ConnectionIO[Option[B]] =
override def optionAlteringExecution[R](fn: PreparedExecution[Option[B]] => PreparedExecution[R])
: ConnectionIO[R] =
outer.optionAlteringExecution(a, fn)
override def nel: ConnectionIO[NonEmptyList[B]] = outer.nel(a)
override def nelAlteringExecution(
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
): ConnectionIO[NonEmptyList[B]] =
override def nelAlteringExecution[R](
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
): ConnectionIO[R] =
outer.nelAlteringExecution(a, fn)
override def map[C](f: B => C): Query0[C] = outer.map(f).toQuery0(a)
override def inspect[R](f: (String, PreparedStatementIO[Unit]) => ConnectionIO[R]): ConnectionIO[R] =
Expand Down Expand Up @@ -386,9 +387,9 @@ object query {
*/
def to[F[_]](implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]]

def toAlteringExecution[F[_]](
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]]
def toAlteringExecution[F[_], R](
fn: PreparedExecution[F[B]] => PreparedExecution[R]
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[R]

/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
* an `Map[(K, V)]` accumulated via the provided `CanBuildFrom`. This is the fastest way to accumulate a
Expand All @@ -397,50 +398,50 @@ object query {
*/
def toMap[K, V](implicit ev: B =:= (K, V), f: FactoryCompat[(K, V), Map[K, V]]): ConnectionIO[Map[K, V]]

def toMapAlteringExecution[K, V](
fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]]
def toMapAlteringExecution[K, V, R](
fn: PreparedExecution[Map[K, V]] => PreparedExecution[R]
)(implicit
ev: B =:= (K, V),
f: FactoryCompat[(K, V), Map[K, V]]
): ConnectionIO[Map[K, V]]
): ConnectionIO[R]

/** Program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding an `F[B]` accumulated via `MonadPlus`
* append. This method is more general but less efficient than `to`.
* @group Results
*/
def accumulate[F[_]: Alternative]: ConnectionIO[F[B]]

def accumulateAlteringExecution[F[_]: Alternative](
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
): ConnectionIO[F[B]]
def accumulateAlteringExecution[F[_]: Alternative, R](
fn: PreparedExecution[F[B]] => PreparedExecution[R]
): ConnectionIO[R]

/** Program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding a unique `B` and raising an exception
* if the resultset does not have exactly one row. See also `option`.
* @group Results
*/
def unique: ConnectionIO[B]

def uniqueAlteringExecution(fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B]
def uniqueAlteringExecution[R](fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R]

/** Program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding an optional `B` and raising an
* exception if the resultset has more than one row. See also `unique`.
* @group Results
*/
def option: ConnectionIO[Option[B]]

def optionAlteringExecution(
fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]]
): ConnectionIO[Option[B]]
def optionAlteringExecution[R](
fn: PreparedExecution[Option[B]] => PreparedExecution[R]
): ConnectionIO[R]

/** Program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding a `NonEmptyList[B]` and raising an
* exception if the resultset does not have at least one row. See also `unique`.
* @group Results
*/
def nel: ConnectionIO[NonEmptyList[B]]

def nelAlteringExecution(
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
): ConnectionIO[NonEmptyList[B]]
def nelAlteringExecution[R](
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
): ConnectionIO[R]

/** @group Transformations */
def map[C](f: B => C): Query0[C]
Expand Down
12 changes: 6 additions & 6 deletions modules/core/src/test/scala/doobie/util/QuerySuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class QuerySuite extends munit.CatsEffectSuite {

test("Query toAlteringExecution (result set operations)") {
var didRun = false
pairQuery.toAlteringExecution[List](
pairQuery.toAlteringExecution[List, List[(String, Int)]](
"x",
{ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
Expand All @@ -78,7 +78,7 @@ class QuerySuite extends munit.CatsEffectSuite {
}
test("Query toMapAlteringExecution (result set operations)") {
var didRun = false
pairQuery.toMapAlteringExecution[String, Int](
pairQuery.toMapAlteringExecution[String, Int, Map[String, Int]](
"x",
{ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
Expand All @@ -92,7 +92,7 @@ class QuerySuite extends munit.CatsEffectSuite {
}
test("Query accumulateAlteringExecution (result set operations)") {
var didRun = false
pairQuery.accumulateAlteringExecution[List](
pairQuery.accumulateAlteringExecution[List, List[(String, Int)]](
"x",
{ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
Expand Down Expand Up @@ -223,7 +223,7 @@ class QuerySuite extends munit.CatsEffectSuite {

test("Query0 toAlteringExecution (result set operations)") {
var didRun = false
val result = pairQuery.toQuery0("x").toAlteringExecution[List]({ preparedExec =>
val result = pairQuery.toQuery0("x").toAlteringExecution[List, List[(String, Int)]]({ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
preparedExec.copy(process = process)
})
Expand All @@ -234,7 +234,7 @@ class QuerySuite extends munit.CatsEffectSuite {
}
test("Query0 toMapAlteringExecution (result set operations)") {
var didRun = false
pairQuery.toQuery0("x").toMapAlteringExecution[String, Int]({ preparedExec =>
pairQuery.toQuery0("x").toMapAlteringExecution[String, Int, Map[String, Int]]({ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
preparedExec.copy(process = process)
})
Expand All @@ -246,7 +246,7 @@ class QuerySuite extends munit.CatsEffectSuite {
}
test("Query0 accumulateAlteringExecution (result set operations)") {
var didRun = false
pairQuery.toQuery0("x").accumulateAlteringExecution[List]({ preparedExec =>
pairQuery.toQuery0("x").accumulateAlteringExecution[List, List[(String, Int)]]({ preparedExec =>
val process = IHRS.delay { didRun = true } *> preparedExec.process
preparedExec.copy(process = process)
})
Expand Down

0 comments on commit 9342af0

Please sign in to comment.