-
Notifications
You must be signed in to change notification settings - Fork 348
/
sqloutput.scala
288 lines (268 loc) · 13.9 KB
/
sqloutput.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
// Copyright (c) 2013-2018 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT
package doobie.free
import cats.~>
import cats.effect.{ Async, ContextShift, ExitCase }
import cats.free.{ Free => FF } // alias because some algebras have an op called Free
import scala.concurrent.ExecutionContext
import java.io.InputStream
import java.io.Reader
import java.lang.String
import java.math.BigDecimal
import java.net.URL
import java.sql.Blob
import java.sql.Clob
import java.sql.Date
import java.sql.NClob
import java.sql.Ref
import java.sql.RowId
import java.sql.SQLData
import java.sql.SQLOutput
import java.sql.SQLType
import java.sql.SQLXML
import java.sql.Struct
import java.sql.Time
import java.sql.Timestamp
import java.sql.{ Array => SqlArray }
@SuppressWarnings(Array("org.wartremover.warts.Overloading"))
object sqloutput { module =>
// Algebra of operations for SQLOutput. Each accepts a visitor as an alternative to pattern-matching.
sealed trait SQLOutputOp[A] {
def visit[F[_]](v: SQLOutputOp.Visitor[F]): F[A]
}
// Free monad over SQLOutputOp.
type SQLOutputIO[A] = FF[SQLOutputOp, A]
// Module of instances and constructors of SQLOutputOp.
object SQLOutputOp {
// Given a SQLOutput we can embed a SQLOutputIO program in any algebra that understands embedding.
implicit val SQLOutputOpEmbeddable: Embeddable[SQLOutputOp, SQLOutput] =
new Embeddable[SQLOutputOp, SQLOutput] {
def embed[A](j: SQLOutput, fa: FF[SQLOutputOp, A]) = Embedded.SQLOutput(j, fa)
}
// Interface for a natural tansformation SQLOutputOp ~> F encoded via the visitor pattern.
// This approach is much more efficient than pattern-matching for large algebras.
trait Visitor[F[_]] extends (SQLOutputOp ~> F) {
final def apply[A](fa: SQLOutputOp[A]): F[A] = fa.visit(this)
// Common
def raw[A](f: SQLOutput => A): F[A]
def embed[A](e: Embedded[A]): F[A]
def delay[A](a: () => A): F[A]
def handleErrorWith[A](fa: SQLOutputIO[A], f: Throwable => SQLOutputIO[A]): F[A]
def raiseError[A](e: Throwable): F[A]
def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]
def asyncF[A](k: (Either[Throwable, A] => Unit) => SQLOutputIO[Unit]): F[A]
def bracketCase[A, B](acquire: SQLOutputIO[A])(use: A => SQLOutputIO[B])(release: (A, ExitCase[Throwable]) => SQLOutputIO[Unit]): F[B]
def shift: F[Unit]
def evalOn[A](ec: ExecutionContext)(fa: SQLOutputIO[A]): F[A]
// SQLOutput
def writeArray(a: SqlArray): F[Unit]
def writeAsciiStream(a: InputStream): F[Unit]
def writeBigDecimal(a: BigDecimal): F[Unit]
def writeBinaryStream(a: InputStream): F[Unit]
def writeBlob(a: Blob): F[Unit]
def writeBoolean(a: Boolean): F[Unit]
def writeByte(a: Byte): F[Unit]
def writeBytes(a: Array[Byte]): F[Unit]
def writeCharacterStream(a: Reader): F[Unit]
def writeClob(a: Clob): F[Unit]
def writeDate(a: Date): F[Unit]
def writeDouble(a: Double): F[Unit]
def writeFloat(a: Float): F[Unit]
def writeInt(a: Int): F[Unit]
def writeLong(a: Long): F[Unit]
def writeNClob(a: NClob): F[Unit]
def writeNString(a: String): F[Unit]
def writeObject(a: AnyRef, b: SQLType): F[Unit]
def writeObject(a: SQLData): F[Unit]
def writeRef(a: Ref): F[Unit]
def writeRowId(a: RowId): F[Unit]
def writeSQLXML(a: SQLXML): F[Unit]
def writeShort(a: Short): F[Unit]
def writeString(a: String): F[Unit]
def writeStruct(a: Struct): F[Unit]
def writeTime(a: Time): F[Unit]
def writeTimestamp(a: Timestamp): F[Unit]
def writeURL(a: URL): F[Unit]
}
// Common operations for all algebras.
final case class Raw[A](f: SQLOutput => A) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.raw(f)
}
final case class Embed[A](e: Embedded[A]) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.embed(e)
}
final case class Delay[A](a: () => A) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.delay(a)
}
final case class HandleErrorWith[A](fa: SQLOutputIO[A], f: Throwable => SQLOutputIO[A]) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.handleErrorWith(fa, f)
}
final case class RaiseError[A](e: Throwable) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.raiseError(e)
}
final case class Async1[A](k: (Either[Throwable, A] => Unit) => Unit) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.async(k)
}
final case class AsyncF[A](k: (Either[Throwable, A] => Unit) => SQLOutputIO[Unit]) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.asyncF(k)
}
final case class BracketCase[A, B](acquire: SQLOutputIO[A], use: A => SQLOutputIO[B], release: (A, ExitCase[Throwable]) => SQLOutputIO[Unit]) extends SQLOutputOp[B] {
def visit[F[_]](v: Visitor[F]) = v.bracketCase(acquire)(use)(release)
}
final case object Shift extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.shift
}
final case class EvalOn[A](ec: ExecutionContext, fa: SQLOutputIO[A]) extends SQLOutputOp[A] {
def visit[F[_]](v: Visitor[F]) = v.evalOn(ec)(fa)
}
// SQLOutput-specific operations.
final case class WriteArray(a: SqlArray) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeArray(a)
}
final case class WriteAsciiStream(a: InputStream) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeAsciiStream(a)
}
final case class WriteBigDecimal(a: BigDecimal) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeBigDecimal(a)
}
final case class WriteBinaryStream(a: InputStream) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeBinaryStream(a)
}
final case class WriteBlob(a: Blob) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeBlob(a)
}
final case class WriteBoolean(a: Boolean) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeBoolean(a)
}
final case class WriteByte(a: Byte) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeByte(a)
}
final case class WriteBytes(a: Array[Byte]) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeBytes(a)
}
final case class WriteCharacterStream(a: Reader) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeCharacterStream(a)
}
final case class WriteClob(a: Clob) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeClob(a)
}
final case class WriteDate(a: Date) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeDate(a)
}
final case class WriteDouble(a: Double) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeDouble(a)
}
final case class WriteFloat(a: Float) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeFloat(a)
}
final case class WriteInt(a: Int) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeInt(a)
}
final case class WriteLong(a: Long) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeLong(a)
}
final case class WriteNClob(a: NClob) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeNClob(a)
}
final case class WriteNString(a: String) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeNString(a)
}
final case class WriteObject(a: AnyRef, b: SQLType) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeObject(a, b)
}
final case class WriteObject1(a: SQLData) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeObject(a)
}
final case class WriteRef(a: Ref) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeRef(a)
}
final case class WriteRowId(a: RowId) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeRowId(a)
}
final case class WriteSQLXML(a: SQLXML) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeSQLXML(a)
}
final case class WriteShort(a: Short) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeShort(a)
}
final case class WriteString(a: String) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeString(a)
}
final case class WriteStruct(a: Struct) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeStruct(a)
}
final case class WriteTime(a: Time) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeTime(a)
}
final case class WriteTimestamp(a: Timestamp) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeTimestamp(a)
}
final case class WriteURL(a: URL) extends SQLOutputOp[Unit] {
def visit[F[_]](v: Visitor[F]) = v.writeURL(a)
}
}
import SQLOutputOp._
// Smart constructors for operations common to all algebras.
val unit: SQLOutputIO[Unit] = FF.pure[SQLOutputOp, Unit](())
def pure[A](a: A): SQLOutputIO[A] = FF.pure[SQLOutputOp, A](a)
def raw[A](f: SQLOutput => A): SQLOutputIO[A] = FF.liftF(Raw(f))
def embed[F[_], J, A](j: J, fa: FF[F, A])(implicit ev: Embeddable[F, J]): FF[SQLOutputOp, A] = FF.liftF(Embed(ev.embed(j, fa)))
def delay[A](a: => A): SQLOutputIO[A] = FF.liftF(Delay(() => a))
def handleErrorWith[A](fa: SQLOutputIO[A], f: Throwable => SQLOutputIO[A]): SQLOutputIO[A] = FF.liftF[SQLOutputOp, A](HandleErrorWith(fa, f))
def raiseError[A](err: Throwable): SQLOutputIO[A] = FF.liftF[SQLOutputOp, A](RaiseError(err))
def async[A](k: (Either[Throwable, A] => Unit) => Unit): SQLOutputIO[A] = FF.liftF[SQLOutputOp, A](Async1(k))
def asyncF[A](k: (Either[Throwable, A] => Unit) => SQLOutputIO[Unit]): SQLOutputIO[A] = FF.liftF[SQLOutputOp, A](AsyncF(k))
def bracketCase[A, B](acquire: SQLOutputIO[A])(use: A => SQLOutputIO[B])(release: (A, ExitCase[Throwable]) => SQLOutputIO[Unit]): SQLOutputIO[B] = FF.liftF[SQLOutputOp, B](BracketCase(acquire, use, release))
val shift: SQLOutputIO[Unit] = FF.liftF[SQLOutputOp, Unit](Shift)
def evalOn[A](ec: ExecutionContext)(fa: SQLOutputIO[A]) = FF.liftF[SQLOutputOp, A](EvalOn(ec, fa))
// Smart constructors for SQLOutput-specific operations.
def writeArray(a: SqlArray): SQLOutputIO[Unit] = FF.liftF(WriteArray(a))
def writeAsciiStream(a: InputStream): SQLOutputIO[Unit] = FF.liftF(WriteAsciiStream(a))
def writeBigDecimal(a: BigDecimal): SQLOutputIO[Unit] = FF.liftF(WriteBigDecimal(a))
def writeBinaryStream(a: InputStream): SQLOutputIO[Unit] = FF.liftF(WriteBinaryStream(a))
def writeBlob(a: Blob): SQLOutputIO[Unit] = FF.liftF(WriteBlob(a))
def writeBoolean(a: Boolean): SQLOutputIO[Unit] = FF.liftF(WriteBoolean(a))
def writeByte(a: Byte): SQLOutputIO[Unit] = FF.liftF(WriteByte(a))
def writeBytes(a: Array[Byte]): SQLOutputIO[Unit] = FF.liftF(WriteBytes(a))
def writeCharacterStream(a: Reader): SQLOutputIO[Unit] = FF.liftF(WriteCharacterStream(a))
def writeClob(a: Clob): SQLOutputIO[Unit] = FF.liftF(WriteClob(a))
def writeDate(a: Date): SQLOutputIO[Unit] = FF.liftF(WriteDate(a))
def writeDouble(a: Double): SQLOutputIO[Unit] = FF.liftF(WriteDouble(a))
def writeFloat(a: Float): SQLOutputIO[Unit] = FF.liftF(WriteFloat(a))
def writeInt(a: Int): SQLOutputIO[Unit] = FF.liftF(WriteInt(a))
def writeLong(a: Long): SQLOutputIO[Unit] = FF.liftF(WriteLong(a))
def writeNClob(a: NClob): SQLOutputIO[Unit] = FF.liftF(WriteNClob(a))
def writeNString(a: String): SQLOutputIO[Unit] = FF.liftF(WriteNString(a))
def writeObject(a: AnyRef, b: SQLType): SQLOutputIO[Unit] = FF.liftF(WriteObject(a, b))
def writeObject(a: SQLData): SQLOutputIO[Unit] = FF.liftF(WriteObject1(a))
def writeRef(a: Ref): SQLOutputIO[Unit] = FF.liftF(WriteRef(a))
def writeRowId(a: RowId): SQLOutputIO[Unit] = FF.liftF(WriteRowId(a))
def writeSQLXML(a: SQLXML): SQLOutputIO[Unit] = FF.liftF(WriteSQLXML(a))
def writeShort(a: Short): SQLOutputIO[Unit] = FF.liftF(WriteShort(a))
def writeString(a: String): SQLOutputIO[Unit] = FF.liftF(WriteString(a))
def writeStruct(a: Struct): SQLOutputIO[Unit] = FF.liftF(WriteStruct(a))
def writeTime(a: Time): SQLOutputIO[Unit] = FF.liftF(WriteTime(a))
def writeTimestamp(a: Timestamp): SQLOutputIO[Unit] = FF.liftF(WriteTimestamp(a))
def writeURL(a: URL): SQLOutputIO[Unit] = FF.liftF(WriteURL(a))
// SQLOutputIO is an Async
implicit val AsyncSQLOutputIO: Async[SQLOutputIO] =
new Async[SQLOutputIO] {
val asyncM = FF.catsFreeMonadForFree[SQLOutputOp]
def bracketCase[A, B](acquire: SQLOutputIO[A])(use: A => SQLOutputIO[B])(release: (A, ExitCase[Throwable]) => SQLOutputIO[Unit]): SQLOutputIO[B] = module.bracketCase(acquire)(use)(release)
def pure[A](x: A): SQLOutputIO[A] = asyncM.pure(x)
def handleErrorWith[A](fa: SQLOutputIO[A])(f: Throwable => SQLOutputIO[A]): SQLOutputIO[A] = module.handleErrorWith(fa, f)
def raiseError[A](e: Throwable): SQLOutputIO[A] = module.raiseError(e)
def async[A](k: (Either[Throwable,A] => Unit) => Unit): SQLOutputIO[A] = module.async(k)
def asyncF[A](k: (Either[Throwable,A] => Unit) => SQLOutputIO[Unit]): SQLOutputIO[A] = module.asyncF(k)
def flatMap[A, B](fa: SQLOutputIO[A])(f: A => SQLOutputIO[B]): SQLOutputIO[B] = asyncM.flatMap(fa)(f)
def tailRecM[A, B](a: A)(f: A => SQLOutputIO[Either[A, B]]): SQLOutputIO[B] = asyncM.tailRecM(a)(f)
def suspend[A](thunk: => SQLOutputIO[A]): SQLOutputIO[A] = asyncM.flatten(module.delay(thunk))
}
// SQLOutputIO is a ContextShift
implicit val ContextShiftSQLOutputIO: ContextShift[SQLOutputIO] =
new ContextShift[SQLOutputIO] {
def shift: SQLOutputIO[Unit] = module.shift
def evalOn[A](ec: ExecutionContext)(fa: SQLOutputIO[A]) = module.evalOn(ec)(fa)
}
}