From 578526d3d8bf8e4a4017465995c37efcf327ddf7 Mon Sep 17 00:00:00 2001 From: Eshu Date: Sat, 7 Oct 2023 17:33:53 +0900 Subject: [PATCH] TextCodec.SeqCodec --- .../main/scala/zio/http/codec/TextCodec.scala | 18 ++++++- .../http/codec/internal/EncoderDecoder.scala | 47 ++++++++++--------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/zio-http/src/main/scala/zio/http/codec/TextCodec.scala b/zio-http/src/main/scala/zio/http/codec/TextCodec.scala index 41d06c0974..5e3968f9ec 100644 --- a/zio-http/src/main/scala/zio/http/codec/TextCodec.scala +++ b/zio-http/src/main/scala/zio/http/codec/TextCodec.scala @@ -16,8 +16,9 @@ package zio.http.codec -import java.util.UUID +import zio.Chunk +import java.util.UUID import zio.stacktracer.TracingImplicits.disableAutoTrace /** @@ -59,6 +60,8 @@ object TextCodec { implicit val uuid: TextCodec[UUID] = UUIDCodec + implicit def seq[A](implicit scalarCodec: TextCodec[A]): TextCodec[Chunk[A]] = SeqCodec(scalarCodec) + final case class Constant(string: String) extends TextCodec[Unit] { def apply(value: String): Unit = if (value == string) () else throw new MatchError(value) @@ -190,4 +193,17 @@ object TextCodec { override def toString(): String = "TextCodec.uuid" } + case class SeqCodec[A](scalarCodec: TextCodec[A]) extends TextCodec[Chunk[A]] { + override def apply(value: String): Chunk[A] = (scalarCodec andThen (Chunk(_)))(value) + + // TODO Find a better naming + override def describe: String = s"a sequence of ${scalarCodec.describe}" + + override def encode(value: Chunk[A]): String = + throw new NotImplementedError("encode is not implemented for SeqCodec") + + override def isDefinedAt(value: String): Boolean = scalarCodec.isDefinedAt(value) + + override def toString: String = s"TextCodec.seq[${scalarCodec.toString}]" + } } diff --git a/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala b/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala index 720ec51e4a..4afe5253bb 100644 --- a/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala +++ b/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala @@ -17,15 +17,11 @@ package zio.http.codec.internal import zio._ -import zio.stacktracer.TracingImplicits.disableAutoTrace - -import zio.stream.ZStream - -import zio.schema.Schema -import zio.schema.codec.{BinaryCodec, Codec} - import zio.http._ import zio.http.codec._ +import zio.schema.Schema +import zio.schema.codec.{BinaryCodec, Codec} +import zio.stream.ZStream private[codec] trait EncoderDecoder[-AtomTypes, Value] { def decode(url: URL, status: Status, method: Method, headers: Headers, body: Body)(implicit @@ -279,18 +275,21 @@ private[codec] object EncoderDecoder { var i = 0 val queries = flattened.query while (i < queries.length) { - val query = queries(i).erase - - val queryParamValue = - queryParams - .getAllOrElse(query.name, Nil) - .collectFirst(query.textCodec) - - queryParamValue match { - case Some(value) => - inputs(i) = value - case None => - throw HttpCodecError.MissingQueryParam(query.name) + val query = queries(i) + + query.textCodec match { + case TextCodec.SeqCodec(scalarCodec) => + queryParams + .getAllOrElse(query.name, Nil) + .map(value => + if (scalarCodec.isDefinedAt(value)) scalarCodec(value) + else throw HttpCodecError.MalformedQueryParam(query.name, query.textCodec), + ) + case scalarCodec => + inputs(i) = queryParams + .getAllOrElse(query.name, Nil) + .collectFirst(scalarCodec) + .getOrElse(throw HttpCodecError.MissingQueryParam(query.name)) } i = i + 1 @@ -475,12 +474,14 @@ private[codec] object EncoderDecoder { var i = 0 while (i < inputs.length) { - val query = flattened.query(i).erase + val query = flattened.query(i) // .erase val input = inputs(i) - val value = query.textCodec.encode(input) - - queryParams = queryParams.add(query.name, value) + queryParams = query.textCodec match { + case TextCodec.SeqCodec(scalarCodec) => + queryParams.addAll(query.name, input.asInstanceOf[Chunk[?]].map(scalarCodec.erase.encode)) + case scalarCodec => queryParams.add(query.name, scalarCodec.erase.encode(input)) + } i = i + 1 }