Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

made a new Transform which receives Req type paramter #610

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 22 additions & 34 deletions code-gen/src/main/scala/scalapb/zio_grpc/ZioCodeGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ZioFilePrinter(
val ZManagedChannel = "scalapb.zio_grpc.ZManagedChannel"
val ZChannel = "scalapb.zio_grpc.ZChannel"
val GTransform = "scalapb.zio_grpc.GTransform"
val RTransform = "scalapb.zio_grpc.RTransform"
val Transform = "scalapb.zio_grpc.Transform"
val Nanos = "java.util.concurrent.TimeUnit.NANOSECONDS"
val serverServiceDef = "_root_.io.grpc.ServerServiceDefinition"
Expand Down Expand Up @@ -246,48 +247,24 @@ class ZioFilePrinter(
)
}

def printClientWithResponseMetadataTransform(
def printServerRTransform(
fp: FunctionalPrinter,
method: MethodDescriptor
): FunctionalPrinter = {
val delegate = s"self.${method.name}"
val newImpl = method.streamType match {
case StreamType.Unary =>
s"f.effect($delegate(request))"
case StreamType.ServerStreaming =>
s"f.stream($delegate(request))"
case StreamType.ClientStreaming =>
s"f.effect($delegate(request))"
case StreamType.Bidirectional =>
s"f.stream($delegate(request))"
}
fp.add(
clientWithResponseMetadataSignature(
method,
"Any"
) + " = " + newImpl
)
}
val reqType = methodInType(method, StatusException)

def printClientTransform(
fp: FunctionalPrinter,
method: MethodDescriptor
): FunctionalPrinter = {
val delegate = s"self.${method.name}"
val newImpl = method.streamType match {
case StreamType.Unary =>
s"f.effect($delegate(request))"
case StreamType.ServerStreaming =>
s"f.stream($delegate(request))"
case StreamType.ClientStreaming =>
s"f.effect($delegate(request))"
case StreamType.Bidirectional =>
s"f.stream($delegate(request))"
val newImpl = method.streamType match {
case StreamType.Unary | StreamType.ClientStreaming =>
s"f.effect((req: $reqType, ctx) => $delegate(req, ctx))(request, context)"
case StreamType.ServerStreaming | StreamType.Bidirectional =>
s"f.stream((req: $reqType, ctx) => $delegate(req, ctx))(request, context)"
}
fp.add(
clientMethodSignature(
methodSignature(
method,
contextType = "Any"
contextType = Some("Context1"),
errorType = Some("Error1")
) + " = " + newImpl
)
}
Expand All @@ -301,6 +278,15 @@ class ZioFilePrinter(
)
).add("}")

def printRTransformMethod(fp: FunctionalPrinter): FunctionalPrinter =
fp.add(
s"def transform[Context1, Error1](f: $RTransform[Context, Error, Context1, Error1]): ${gtraitName.fullName}[Context1, Error1] = new ${gtraitName.fullName}[Context1, Error1] {"
).indented(
_.print(service.getMethods().asScala.toVector)(
printServerRTransform
)
).add("}")

def print(fp: FunctionalPrinter): FunctionalPrinter =
fp.add(
s"trait ${gtraitName.name}[-Context, +Error] extends scalapb.zio_grpc.GenericGeneratedService[Context, Error, ${gtraitName.name}] {"
Expand All @@ -314,6 +300,8 @@ class ZioFilePrinter(
)
.add("")
.call(printGTransformMethod)
.add("")
.call(printRTransformMethod)
).add("}")
.add("")
.add(
Expand Down
90 changes: 90 additions & 0 deletions core/src/main/scala/scalapb/zio_grpc/transforms.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,96 @@ object GTransform {
}
}

/** Describes a transformation for all effects and streams of a generic service.
*
* Instances of this class can be used to apply a transformation to all methods of a service to generate a new
* "decorated" service. This can be used for pre- or post-processing of requests/response or to transform the context.
*
* [[RTransform]] is different from [[GTransform]] in that users can access to the request body while decorating
* service using [[RTransform]]. This is especially useful for request / resposne logging.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is especially useful -> this can be used
resposne -> response

*/
trait RTransform[+ContextIn, -ErrorIn, -ContextOut, +ErrorOut] {
self =>
def effect[Req, Resp](
io: (Req, ContextIn) => ZIO[Any, ErrorIn, Resp]
): (Req, ContextOut) => ZIO[Any, ErrorOut, Resp]

def stream[Req, Resp](
io: (Req, ContextIn) => ZStream[Any, ErrorIn, Resp]
): (Req, ContextOut) => ZStream[Any, ErrorOut, Resp]

def andThen[ContextIn2 <: ContextOut, ErrorIn2 >: ErrorOut, ContextOut2, ErrorOut2](
other: RTransform[ContextIn2, ErrorIn2, ContextOut2, ErrorOut2]
): RTransform[ContextIn, ErrorIn, ContextOut2, ErrorOut2] =
new RTransform[ContextIn, ErrorIn, ContextOut2, ErrorOut2] {
def effect[Req, Resp](
io: (Req, ContextIn) => ZIO[Any, ErrorIn, Resp]
): (Req, ContextOut2) => ZIO[Any, ErrorOut2, Resp] =
other.effect(self.effect(io))

def stream[Req, Resp](
io: (Req, ContextIn) => ZStream[Any, ErrorIn, Resp]
): (Req, ContextOut2) => ZStream[Any, ErrorOut2, Resp] =
other.stream(self.stream(io))
}

def compose[ContextIn2, ErrorIn2, ContextOut2 >: ContextIn, ErrorOut2 <: ErrorIn](
other: RTransform[ContextIn2, ErrorIn2, ContextOut2, ErrorOut2]
): RTransform[ContextIn2, ErrorIn2, ContextOut, ErrorOut] = other.andThen(self)
}

object RTransform {

def identity[C, E]: RTransform[C, E, C, E] = new RTransform[C, E, C, E] {
def effect[Req, Resp](io: (Req, C) => ZIO[Any, E, Resp]): (Req, C) => ZIO[Any, E, Resp] = io
def stream[Req, Resp](io: (Req, C) => ZStream[Any, E, Resp]): (Req, C) => ZStream[Any, E, Resp] = io
}

// Returns a RTransform that effectfully transforms the context parameter
def apply[ContextIn, Error, ContextOut](
f: ContextOut => ZIO[Any, Error, ContextIn]
): RTransform[ContextIn, Error, ContextOut, Error] =
new RTransform[ContextIn, Error, ContextOut, Error] {
def effect[Req, Resp](
io: (Req, ContextIn) => ZIO[Any, Error, Resp]
): (Req, ContextOut) => ZIO[Any, Error, Resp] = { (req, ctx) =>
f(ctx).flatMap(newCtx => io(req, newCtx))
}

def stream[Req, Resp](
io: (Req, ContextIn) => ZStream[Any, Error, Resp]
): (Req, ContextOut) => ZStream[Any, Error, Resp] = { (req, ctx) =>
ZStream.fromZIO(f(ctx)).flatMap(newCtx => io(req, newCtx))
}
}

// Returns a RTransform that maps the error parameter.
def mapError[C, E1, E2](f: E1 => E2): RTransform[C, E1, C, E2] = new RTransform[C, E1, C, E2] {
def effect[Req, Resp](io: (Req, C) => zio.ZIO[Any, E1, Resp]): (Req, C) => zio.ZIO[Any, E2, Resp] = { (req, ctx) =>
io(req, ctx).mapError(f)
}

def stream[Req, Resp](
io: (Req, C) => zio.stream.ZStream[Any, E1, Resp]
): (Req, C) => zio.stream.ZStream[Any, E2, Resp] = { (req, ctx) =>
io(req, ctx).mapError(f)
}
}

// Returns a RTransform that effectfully maps the error parameter.
def mapErrorZIO[C, E1, E2](f: E1 => zio.UIO[E2]): RTransform[C, E1, C, E2] = new RTransform[C, E1, C, E2] {
def effect[Req, Resp](io: (Req, C) => zio.ZIO[Any, E1, Resp]): (Req, C) => zio.ZIO[Any, E2, Resp] = { (req, ctx) =>
io(req, ctx).flatMapError(f)
}

def stream[Req, Resp](
io: (Req, C) => zio.stream.ZStream[Any, E1, Resp]
): (Req, C) => zio.stream.ZStream[Any, E2, Resp] = { (req, ctx) =>
io(req, ctx).catchAll(e => ZStream.fromZIO(f(e).flatMap(ZIO.fail(_))))
}
}
}

object ZTransform {
def apply[ContextIn, ContextOut](
f: ContextOut => ZIO[Any, StatusException, ContextIn]
Expand Down
Loading