Skip to content

Commit 2f1ee69

Browse files
committed
Query' altered execution: Allow changing result type
1 parent d685883 commit 2f1ee69

File tree

2 files changed

+73
-60
lines changed

2 files changed

+73
-60
lines changed

modules/core/src/main/scala/doobie/util/query.scala

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ object query {
105105
toConnectionIO(a, IHRS.build[F, B])
106106
}
107107

108-
/** Just like `to` but allowing to alter `PreparedExecution`.
108+
/** Like [[to]], but allow altering various parts of the execute steps before it is run
109109
*/
110-
def toAlteringExecution[F[_]](
110+
def toAlteringExecution[F[_], R](
111111
a: A,
112-
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
113-
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]] = {
112+
fn: PreparedExecution[F[B]] => PreparedExecution[R]
113+
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[R] = {
114114
toConnectionIOAlteringExecution(a, IHRS.build[F, B], fn)
115115
}
116116

@@ -122,15 +122,15 @@ object query {
122122
def toMap[K, V](a: A)(implicit ev: B =:= (K, V), f: FactoryCompat[(K, V), Map[K, V]]): ConnectionIO[Map[K, V]] =
123123
toConnectionIO(a, IHRS.buildPair[Map, K, V](f, read.map(ev)))
124124

125-
/** Just like `toMap` but allowing to alter `PreparedExecution`.
125+
/** Like [[toMap]], but allow altering various parts of the execute steps before it is run
126126
*/
127-
def toMapAlteringExecution[K, V](
127+
def toMapAlteringExecution[K, V, R](
128128
a: A,
129-
fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]]
129+
fn: PreparedExecution[Map[K, V]] => PreparedExecution[R]
130130
)(implicit
131131
ev: B =:= (K, V),
132132
f: FactoryCompat[(K, V), Map[K, V]]
133-
): ConnectionIO[Map[K, V]] =
133+
): ConnectionIO[R] =
134134
toConnectionIOAlteringExecution(a, IHRS.buildPair[Map, K, V](f, read.map(ev)), fn)
135135

136136
/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
@@ -140,12 +140,12 @@ object query {
140140
def accumulate[F[_]: Alternative](a: A): ConnectionIO[F[B]] =
141141
toConnectionIO(a, IHRS.accumulate[F, B])
142142

143-
/** Just like `accumulate` but allowing to alter `PreparedExecution`.
143+
/** Like [[accumulate]], but allow altering various parts of the execute steps before it is run
144144
*/
145-
def accumulateAlteringExecution[F[_]: Alternative](
145+
def accumulateAlteringExecution[F[_]: Alternative, R](
146146
a: A,
147-
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
148-
): ConnectionIO[F[B]] =
147+
fn: PreparedExecution[F[B]] => PreparedExecution[R]
148+
): ConnectionIO[R] =
149149
toConnectionIOAlteringExecution(a, IHRS.accumulate[F, B], fn)
150150

151151
/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
@@ -155,9 +155,9 @@ object query {
155155
def unique(a: A): ConnectionIO[B] =
156156
toConnectionIO(a, IHRS.getUnique[B])
157157

158-
/** Just like `unique` but allowing to alter `PreparedExecution`.
158+
/** Like [[unique]], but allow altering various parts of the execute steps before it is run
159159
*/
160-
def uniqueAlteringExecution(a: A, fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B] =
160+
def uniqueAlteringExecution[R](a: A, fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R] =
161161
toConnectionIOAlteringExecution(a, IHRS.getUnique[B], fn)
162162

163163
/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
@@ -167,12 +167,12 @@ object query {
167167
def option(a: A): ConnectionIO[Option[B]] =
168168
toConnectionIO(a, IHRS.getOption[B])
169169

170-
/** Just like `option` but allowing to alter `PreparedExecution`.
170+
/** Like [[option]], but allow altering various parts of the execute steps before it is run
171171
*/
172-
def optionAlteringExecution(
172+
def optionAlteringExecution[R](
173173
a: A,
174-
fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]]
175-
): ConnectionIO[Option[B]] =
174+
fn: PreparedExecution[Option[B]] => PreparedExecution[R]
175+
): ConnectionIO[R] =
176176
toConnectionIOAlteringExecution(a, IHRS.getOption[B], fn)
177177

178178
/** Apply the argument `a` to construct a program in `[[doobie.free.connection.ConnectionIO ConnectionIO]]` yielding
@@ -183,22 +183,22 @@ object query {
183183
def nel(a: A): ConnectionIO[NonEmptyList[B]] =
184184
toConnectionIO(a, IHRS.nel[B])
185185

186-
/** Just like `nel` but allowing to alter `PreparedExecution`.
186+
/** Like [[nel]], but allow altering various parts of the execute steps before it is run
187187
*/
188-
def nelAlteringExecution(
188+
def nelAlteringExecution[R](
189189
a: A,
190-
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
191-
): ConnectionIO[NonEmptyList[B]] =
190+
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
191+
): ConnectionIO[R] =
192192
toConnectionIOAlteringExecution(a, IHRS.nel[B], fn)
193193

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

197-
private def toConnectionIOAlteringExecution[C](
197+
private def toConnectionIOAlteringExecution[C, R](
198198
a: A,
199199
rsio: ResultSetIO[C],
200-
fn: PreparedExecution[C] => PreparedExecution[C]
201-
): ConnectionIO[C] =
200+
fn: PreparedExecution[C] => PreparedExecution[R]
201+
): ConnectionIO[R] =
202202
IHC.executeWithResultSet(fn(preparedExecution(sql, a, rsio)), mkLoggingInfo(a))
203203

204204
private def preparedExecution[C](sql: String, a: A, rsio: ResultSetIO[C]): PreparedExecution[C] =
@@ -248,34 +248,35 @@ object query {
248248
override def outputAnalysis: ConnectionIO[Analysis] = outer.outputAnalysis
249249
override def streamWithChunkSize(n: Int): Stream[ConnectionIO, B] = outer.streamWithChunkSize(a, n)
250250
override def accumulate[F[_]: Alternative]: ConnectionIO[F[B]] = outer.accumulate[F](a)
251-
override def accumulateAlteringExecution[F[_]: Alternative](
252-
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
253-
): ConnectionIO[F[B]] = outer.accumulateAlteringExecution(a, fn)
251+
override def accumulateAlteringExecution[F[_]: Alternative, R](
252+
fn: PreparedExecution[F[B]] => PreparedExecution[R]
253+
): ConnectionIO[R] = outer.accumulateAlteringExecution(a, fn)
254254
override def to[F[_]](implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]] = outer.to[F](a)
255-
override def toAlteringExecution[F[_]](fn: PreparedExecution[F[B]] => PreparedExecution[F[B]])(implicit
255+
override def toAlteringExecution[F[_], R](fn: PreparedExecution[F[B]] => PreparedExecution[R])(implicit
256256
f: FactoryCompat[B, F[B]]
257-
): ConnectionIO[F[B]] =
257+
): ConnectionIO[R] =
258258
outer.toAlteringExecution(a, fn)
259259
override def toMap[K, V](implicit
260260
ev: B =:= (K, V),
261261
f: FactoryCompat[(K, V), Map[K, V]]
262262
): ConnectionIO[Map[K, V]] = outer.toMap(a)
263-
override def toMapAlteringExecution[K, V](fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]])(
263+
264+
override def toMapAlteringExecution[K, V, R](fn: PreparedExecution[Map[K, V]] => PreparedExecution[R])(
264265
implicit
265266
ev: B =:= (K, V),
266267
f: FactoryCompat[(K, V), Map[K, V]]
267-
): ConnectionIO[Map[K, V]] = outer.toMapAlteringExecution(a, fn)
268+
): ConnectionIO[R] = outer.toMapAlteringExecution(a, fn)
268269
override def unique: ConnectionIO[B] = outer.unique(a)
269-
override def uniqueAlteringExecution(fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B] =
270+
override def uniqueAlteringExecution[R](fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R] =
270271
outer.uniqueAlteringExecution(a, fn)
271272
override def option: ConnectionIO[Option[B]] = outer.option(a)
272-
override def optionAlteringExecution(fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]])
273-
: ConnectionIO[Option[B]] =
273+
override def optionAlteringExecution[R](fn: PreparedExecution[Option[B]] => PreparedExecution[R])
274+
: ConnectionIO[R] =
274275
outer.optionAlteringExecution(a, fn)
275276
override def nel: ConnectionIO[NonEmptyList[B]] = outer.nel(a)
276-
override def nelAlteringExecution(
277-
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
278-
): ConnectionIO[NonEmptyList[B]] =
277+
override def nelAlteringExecution[R](
278+
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
279+
): ConnectionIO[R] =
279280
outer.nelAlteringExecution(a, fn)
280281
override def map[C](f: B => C): Query0[C] = outer.map(f).toQuery0(a)
281282
override def inspect[R](f: (String, PreparedStatementIO[Unit]) => ConnectionIO[R]): ConnectionIO[R] =
@@ -386,9 +387,11 @@ object query {
386387
*/
387388
def to[F[_]](implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]]
388389

389-
def toAlteringExecution[F[_]](
390-
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
391-
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[F[B]]
390+
/** Like [[to]], but allow altering various parts of the execute steps before it is run
391+
*/
392+
def toAlteringExecution[F[_], R](
393+
fn: PreparedExecution[F[B]] => PreparedExecution[R]
394+
)(implicit f: FactoryCompat[B, F[B]]): ConnectionIO[R]
392395

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

400-
def toMapAlteringExecution[K, V](
401-
fn: PreparedExecution[Map[K, V]] => PreparedExecution[Map[K, V]]
403+
/** Like [[toMap]], but allow altering various parts of the execute steps before it is run
404+
*/
405+
def toMapAlteringExecution[K, V, R](
406+
fn: PreparedExecution[Map[K, V]] => PreparedExecution[R]
402407
)(implicit
403408
ev: B =:= (K, V),
404409
f: FactoryCompat[(K, V), Map[K, V]]
405-
): ConnectionIO[Map[K, V]]
410+
): ConnectionIO[R]
406411

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

413-
def accumulateAlteringExecution[F[_]: Alternative](
414-
fn: PreparedExecution[F[B]] => PreparedExecution[F[B]]
415-
): ConnectionIO[F[B]]
418+
/** Like [[to]], but allow altering various parts of the execute steps before it is run
419+
*/
420+
def accumulateAlteringExecution[F[_]: Alternative, R](
421+
fn: PreparedExecution[F[B]] => PreparedExecution[R]
422+
): ConnectionIO[R]
416423

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

423-
def uniqueAlteringExecution(fn: PreparedExecution[B] => PreparedExecution[B]): ConnectionIO[B]
430+
/** Like [[unique]], but allow altering various parts of the execute steps before it is run
431+
*/
432+
def uniqueAlteringExecution[R](fn: PreparedExecution[B] => PreparedExecution[R]): ConnectionIO[R]
424433

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

431-
def optionAlteringExecution(
432-
fn: PreparedExecution[Option[B]] => PreparedExecution[Option[B]]
433-
): ConnectionIO[Option[B]]
440+
/** Like [[option]], but allow altering various parts of the execute steps before it is run
441+
*/
442+
def optionAlteringExecution[R](
443+
fn: PreparedExecution[Option[B]] => PreparedExecution[R]
444+
): ConnectionIO[R]
434445

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

441-
def nelAlteringExecution(
442-
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[NonEmptyList[B]]
443-
): ConnectionIO[NonEmptyList[B]]
452+
/** Like [[nel]], but allow altering various parts of the execute steps before it is run
453+
*/
454+
def nelAlteringExecution[R](
455+
fn: PreparedExecution[NonEmptyList[B]] => PreparedExecution[R]
456+
): ConnectionIO[R]
444457

445458
/** @group Transformations */
446459
def map[C](f: B => C): Query0[C]

modules/core/src/test/scala/doobie/util/QuerySuite.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class QuerySuite extends munit.CatsEffectSuite {
6464

6565
test("Query toAlteringExecution (result set operations)") {
6666
var didRun = false
67-
pairQuery.toAlteringExecution[List](
67+
pairQuery.toAlteringExecution[List, List[(String, Int)]](
6868
"x",
6969
{ preparedExec =>
7070
val process = IHRS.delay { didRun = true } *> preparedExec.process
@@ -78,7 +78,7 @@ class QuerySuite extends munit.CatsEffectSuite {
7878
}
7979
test("Query toMapAlteringExecution (result set operations)") {
8080
var didRun = false
81-
pairQuery.toMapAlteringExecution[String, Int](
81+
pairQuery.toMapAlteringExecution[String, Int, Map[String, Int]](
8282
"x",
8383
{ preparedExec =>
8484
val process = IHRS.delay { didRun = true } *> preparedExec.process
@@ -92,7 +92,7 @@ class QuerySuite extends munit.CatsEffectSuite {
9292
}
9393
test("Query accumulateAlteringExecution (result set operations)") {
9494
var didRun = false
95-
pairQuery.accumulateAlteringExecution[List](
95+
pairQuery.accumulateAlteringExecution[List, List[(String, Int)]](
9696
"x",
9797
{ preparedExec =>
9898
val process = IHRS.delay { didRun = true } *> preparedExec.process
@@ -223,7 +223,7 @@ class QuerySuite extends munit.CatsEffectSuite {
223223

224224
test("Query0 toAlteringExecution (result set operations)") {
225225
var didRun = false
226-
val result = pairQuery.toQuery0("x").toAlteringExecution[List]({ preparedExec =>
226+
val result = pairQuery.toQuery0("x").toAlteringExecution[List, List[(String, Int)]]({ preparedExec =>
227227
val process = IHRS.delay { didRun = true } *> preparedExec.process
228228
preparedExec.copy(process = process)
229229
})
@@ -234,7 +234,7 @@ class QuerySuite extends munit.CatsEffectSuite {
234234
}
235235
test("Query0 toMapAlteringExecution (result set operations)") {
236236
var didRun = false
237-
pairQuery.toQuery0("x").toMapAlteringExecution[String, Int]({ preparedExec =>
237+
pairQuery.toQuery0("x").toMapAlteringExecution[String, Int, Map[String, Int]]({ preparedExec =>
238238
val process = IHRS.delay { didRun = true } *> preparedExec.process
239239
preparedExec.copy(process = process)
240240
})
@@ -246,7 +246,7 @@ class QuerySuite extends munit.CatsEffectSuite {
246246
}
247247
test("Query0 accumulateAlteringExecution (result set operations)") {
248248
var didRun = false
249-
pairQuery.toQuery0("x").accumulateAlteringExecution[List]({ preparedExec =>
249+
pairQuery.toQuery0("x").accumulateAlteringExecution[List, List[(String, Int)]]({ preparedExec =>
250250
val process = IHRS.delay { didRun = true } *> preparedExec.process
251251
preparedExec.copy(process = process)
252252
})

0 commit comments

Comments
 (0)