Skip to content

Commit

Permalink
Add additional type parameter to Route
Browse files Browse the repository at this point in the history
This represents the type of values used to construct the entity, which
can differ from the type of values extracted from the entity. Used when
constructing a request to a route, such as we generating a call from a
client.
  • Loading branch information
noelwelsh committed Dec 4, 2023
1 parent 682df48 commit 3c35cc9
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 27 deletions.
23 changes: 13 additions & 10 deletions core/shared/src/main/scala/krop/route/Request.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ import org.http4s.{Request as Http4sRequest}
* @tparam E
* The type of values extracted from other parts of the request (e.g. headers
* or entity).
* @tparam O
* The type of values that construct the entity. Used when creating a request
* that calls the Route containing this Request.
*/
final class Request[P <: Tuple, Q, E](
final class Request[P <: Tuple, Q, E, O](
val method: Method,
val path: Path[P, Q],
val entity: Entity[E, ?]
val entity: Entity[E, O]
) {
import Request.NormalizedAppend

Expand Down Expand Up @@ -90,13 +93,13 @@ final class Request[P <: Tuple, Q, E](
def describe: String =
s"${method.toString()} ${path.describe} ${entity.encoder.contentType.map(_.mediaType).getOrElse("")}"

def withEntity[E2](entity: Entity[E2, ?]): Request[P, Q, E2] =
def withEntity[E2, O2](entity: Entity[E2, O2]): Request[P, Q, E2, O2] =
new Request(method, path, entity)

def withMethod(method: Method): Request[P, Q, E] =
def withMethod(method: Method): Request[P, Q, E, O] =
new Request(method, path, entity)

def withPath[P2 <: Tuple, Q2](path: Path[P2, Q2]): Request[P2, Q2, E] =
def withPath[P2 <: Tuple, Q2](path: Path[P2, Q2]): Request[P2, Q2, E, O] =
new Request(method, path, entity)

}
Expand All @@ -110,22 +113,22 @@ object Request {
case _ => Tuple.Append[A, B]
}

def delete[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit] =
def delete[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit, Unit] =
Request.method(Method.DELETE, path)

def get[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit] =
def get[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit, Unit] =
Request.method(Method.GET, path)

def post[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit] =
def post[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit, Unit] =
Request.method(Method.POST, path)

def put[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit] =
def put[P <: Tuple, Q](path: Path[P, Q]): Request[P, Q, Unit, Unit] =
Request.method(Method.PUT, path)

def method[P <: Tuple, Q](
method: Method,
path: Path[P, Q]
): Request[P, Q, Unit] =
): Request[P, Q, Unit, Unit] =
new Request(method, path, Entity.unit)

}
28 changes: 15 additions & 13 deletions core/shared/src/main/scala/krop/route/Route.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ import org.http4s.HttpRoutes
/** Type alias for a [[package.Route]] that has extracts no [[package.Entity]]
* from the request.
*/
type PathRoute[P <: Tuple, R] = Route[P, Unit, Unit, R]
type PathRoute[P <: Tuple, R] = Route[P, Unit, Unit, Unit, R]

/** Type alias for a [[package.Route]] that has extracts no [[package.Path]] or
* [[package.Entity]]] parameters from the request.
*/
type SimpleRoute[P, R] = Route[EmptyTuple, Unit, Unit, R]
type SimpleRoute[P, R] = Route[EmptyTuple, Unit, Unit, Unit, R]

/** Type alias for a [[package.Route]] that has extracts no [[package.Entity]]
* from the request and extracts a single parameter from the [[package.Path]].
Expand All @@ -53,9 +53,11 @@ type Path1Route[P, R] = PathRoute[Tuple1[P], R]
* The type of the [[package.Entity]] extracted from the request.
* @tparam O
* The type of the parameters used to build the [[package.Response]].
* @tparam R
* The type of the parameters used to build the [[package.Response]].
*/
final class Route[P <: Tuple, Q, E, R](
val request: Request[P, Q, E],
final class Route[P <: Tuple, Q, E, O, R](
val request: Request[P, Q, E, O],
val response: Response[R],
val handler: Request.NormalizedAppend[
Request.NormalizedAppend[P, Q],
Expand All @@ -72,7 +74,7 @@ final class Route[P <: Tuple, Q, E, R](
/** Try this Route. If it fails to match, pass control to the given
* [[package.Route]].
*/
def orElse(that: Route[?, ?, ?, ?]): Routes =
def orElse(that: Route[?, ?, ?, ?, ?]): Routes =
this.orElse(that.toRoutes)

/** Try this Route. If it fails to match, pass control to the
Expand Down Expand Up @@ -142,32 +144,32 @@ final class Route[P <: Tuple, Q, E, R](
object Route {
import Request.NormalizedAppend

def apply[P <: Tuple, Q, E, R](
request: Request[P, Q, E],
def apply[P <: Tuple, Q, E, O, R](
request: Request[P, Q, E, O],
response: Response[R]
)(using
ta: TupleApply[NormalizedAppend[NormalizedAppend[P, Q], E], R],
taIO: TupleApply[NormalizedAppend[NormalizedAppend[P, Q], E], IO[R]]
): RouteBuilder[P, Q, E, ta.Fun, taIO.Fun, R] =
): RouteBuilder[P, Q, E, O, ta.Fun, taIO.Fun, R] =
RouteBuilder(request, response, ta, taIO)

final class RouteBuilder[P <: Tuple, Q, E, F, FIO, R](
request: Request[P, Q, E],
final class RouteBuilder[P <: Tuple, Q, E, O, F, FIO, R](
request: Request[P, Q, E, O],
response: Response[R],
ta: TupleApply.Aux[NormalizedAppend[NormalizedAppend[P, Q], E], F, R],
taIO: TupleApply.Aux[NormalizedAppend[NormalizedAppend[P, Q], E], FIO, IO[
R
]]
) {
def handle(f: F): Route[P, Q, E, R] =
def handle(f: F): Route[P, Q, E, O, R] =
new Route(request, response, i => IO.pure(ta.tuple(f)(i)))

def handleIO[A](f: FIO): Route[P, Q, E, R] =
def handleIO[A](f: FIO): Route[P, Q, E, O, R] =
new Route(request, response, taIO.tuple(f))

def passthrough(using
pb: PassthroughBuilder[NormalizedAppend[NormalizedAppend[P, Q], E], R]
): Route[P, Q, E, R] =
): Route[P, Q, E, O, R] =
new Route(request, response, pb.build)
}
}
6 changes: 3 additions & 3 deletions core/shared/src/main/scala/krop/route/Routes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ import krop.tool.NotFound
import org.http4s.HttpRoutes

/** [[package.Routes]] are a collection of zero or more [[package.Route]]. */
final class Routes(val routes: Chain[Route[?, ?, ?, ?]]) {
final class Routes(val routes: Chain[Route[?, ?, ?, ?, ?]]) {

/** Create a [[package.Routes]] that tries first these routes, and if they
* fail to match, the route in the given parameter.
*/
def orElse(that: Route[?, ?, ?, ?]): Routes =
def orElse(that: Route[?, ?, ?, ?, ?]): Routes =
Routes(this.routes :+ that)

/** Create a [[package.Routes]] that tries first these routes, and if they
Expand Down Expand Up @@ -63,5 +63,5 @@ final class Routes(val routes: Chain[Route[?, ?, ?, ?]]) {
object Routes {

/** The empty [[package.Routes]], which don't match any request. */
val empty: Routes = new Routes(Chain.empty[Route[?, ?, ?, ?]])
val empty: Routes = new Routes(Chain.empty[Route[?, ?, ?, ?, ?]])
}
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.9.6
sbt.version=1.9.7

0 comments on commit 3c35cc9

Please sign in to comment.