1
|
|
import cats._
|
2
|
|
import cats.data.{EitherK, NonEmptyList}
|
3
|
|
import cats.free.Free
|
4
|
|
import cats.effect.Sync
|
5
|
|
import contextual._
|
6
|
|
|
7
|
|
package object hammock {
|
8
|
|
|
9
|
|
import hammock.marshalling._
|
10
|
|
import hammock.InterpTrans
|
11
|
|
|
12
|
|
type HammockF[A] = EitherK[HttpF, MarshallF, A]
|
13
|
|
|
14
|
|
implicit class HttpRequestIOSyntax[A](fa: Free[HttpF, A]) {
|
15
|
|
def exec[F[_]: Sync](implicit interp: InterpTrans[F]): F[A] =
|
16
|
0
|
fa foldMap interp.trans
|
17
|
|
}
|
18
|
|
|
19
|
|
implicit class HammockFSyntax[A](fa: Free[HammockF, A]) {
|
20
|
|
def exec[F[_]: Sync](implicit NT: HammockF ~> F): F[A] =
|
21
|
0
|
fa foldMap NT
|
22
|
|
}
|
23
|
|
|
24
|
|
implicit class AsSyntaxOnHttpF[F[_], A](fa: Free[F, HttpResponse])(
|
25
|
|
implicit
|
26
|
|
H: InjectK[HttpF, F]) {
|
27
|
|
def as[B](implicit D: Decoder[B], M: MarshallC[EitherK[F, MarshallF, *]]): Free[EitherK[F, MarshallF, *], B] =
|
28
|
0
|
fa.inject[EitherK[F, MarshallF, *]] flatMap { response =>
|
29
|
0
|
M.unmarshall(response.entity)
|
30
|
|
}
|
31
|
|
}
|
32
|
|
|
33
|
|
implicit def hammockNT[F[_]: Sync](
|
34
|
|
implicit H: InterpTrans[F],
|
35
|
|
M: MarshallF ~> F
|
36
|
0
|
): HammockF ~> F = H.trans or M
|
37
|
|
|
38
|
|
object UriContext extends Context
|
39
|
|
|
40
|
|
object UriInterpolator extends Interpolator {
|
41
|
|
type Output = Uri
|
42
|
|
type ContextType = UriContext.type
|
43
|
|
type Input = String
|
44
|
|
def contextualize(interpolation: StaticInterpolation) = {
|
45
|
1
|
interpolation.parts.foldLeft(List.empty[ContextType]) {
|
46
|
1
|
case (contexts, Hole(_, _)) => UriContext :: contexts
|
47
|
|
case (contexts, _) => contexts
|
48
|
|
}
|
49
|
|
}
|
50
|
|
|
51
|
|
def evaluate(interpolation: RuntimeInterpolation): Uri = {
|
52
|
|
val substituted = interpolation.literals
|
53
|
|
.zipAll(interpolation.substitutions, "", "")
|
54
|
|
.flatMap(x => List(x._1, x._2))
|
55
|
1
|
.mkString("")
|
56
|
1
|
Uri.fromString(substituted).right.get
|
57
|
|
}
|
58
|
|
|
59
|
|
}
|
60
|
|
|
61
|
1
|
implicit val embedString = UriInterpolator.embed[String](Case(UriContext, UriContext) { x =>
|
62
|
|
x
|
63
|
|
})
|
64
|
|
|
65
|
|
/**
|
66
|
|
* Unsafe string interpolator allowing uri parsing. It's unsafe
|
67
|
|
* because in case of any error happen (a Left is returned by the
|
68
|
|
* `fromString` method), it will throw an exception.
|
69
|
|
*
|
70
|
|
* {{{
|
71
|
|
* scala> uri"http://user:pass@pepegar.com/path?page=4#index"
|
72
|
|
* res1: hammock.Uri = Uri(Some(http),Some(user:pass),pepegar.com/path,Map(page -> 4),Some(index))
|
73
|
|
* }}}
|
74
|
|
*/
|
75
|
|
implicit class UriStringContext(sc: StringContext) {
|
76
|
0
|
val uri = Prefix(UriInterpolator, sc)
|
77
|
|
}
|
78
|
|
|
79
|
|
/**
|
80
|
|
* Methods providing URI query parameters building syntax
|
81
|
|
* Used in [[Uri.?]] method
|
82
|
|
**/
|
83
|
|
implicit class UriQueryParamsBuilder(val self: NonEmptyList[(String, String)]) extends AnyVal {
|
84
|
0
|
def &(param: (String, String)): NonEmptyList[(String, String)] = param :: self
|
85
|
|
}
|
86
|
|
implicit class UriQueryInitBuilder(val self: (String, String)) extends AnyVal {
|
87
|
0
|
def &(param: (String, String)): NonEmptyList[(String, String)] = NonEmptyList(self, param :: Nil)
|
88
|
|
}
|
89
|
|
}
|