Skip to content

Commit

Permalink
Special case encode optional for HttpCodec.Content (#3144) (#3167)
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil authored Sep 27, 2024
1 parent 5e7f147 commit e1afcf2
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1398,8 +1398,7 @@ object OpenAPIGenSpec extends ZIOSpecDefault {
| "width",
| "height",
| "metadata"
| ],
| "description" : "Test doc\n\n"
| ]
| }
| }
| }
Expand Down
13 changes: 13 additions & 0 deletions zio-http/shared/src/main/scala/zio/http/codec/HttpCodec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,19 @@ object HttpCodec extends ContentCodecs with HeaderCodecs with MethodCodecs with
def tag: AtomTag = AtomTag.Content

def index(index: Int): Content[A] = copy(index = index)

/**
* Returns a new codec, where the value produced by this one is optional.
*/
override def optional: HttpCodec[HttpCodecType.Content, Option[A]] =
Annotated(
Content(
codec.optional,
name,
index,
),
Metadata.Optional(),
)
}
private[http] final case class ContentStream[A](
codec: HttpContentCodec[A],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,36 @@ sealed trait HttpContentCodec[A] { self =>
choices.headOption.map(_._2).getOrElse {
throw new IllegalArgumentException(s"No codec defined")
}

def optional: HttpContentCodec[Option[A]] =
self match {
case HttpContentCodec.Choices(choices) =>
HttpContentCodec.Choices(
choices.map { case (mediaType, BinaryCodecWithSchema(fromConfig, schema)) =>
mediaType -> BinaryCodecWithSchema(fromConfig.andThen(optBinaryCodec), schema.optional)
},
)
case HttpContentCodec.Filtered(codec, mediaType) =>
HttpContentCodec.Filtered(codec.optional, mediaType)
}

private def optBinaryCodec(bc: BinaryCodec[A]): BinaryCodec[Option[A]] = new BinaryCodec[Option[A]] {
override def encode(value: Option[A]): Chunk[Byte] = value match {
case Some(a) => bc.encode(a)
case None => Chunk.empty
}

override def decode(bytes: Chunk[Byte]): Either[DecodeError, Option[A]] =
if (bytes.isEmpty) Right(None)
else bc.decode(bytes).map(Some(_))

override def streamDecoder: ZPipeline[Any, DecodeError, Byte, Option[A]] =
ZPipeline.chunks[Byte].map(bc.decode).map(_.toOption)

override def streamEncoder: ZPipeline[Any, Nothing, Option[A], Byte] =
ZPipeline.identity[Option[A]].map(_.fold(Chunk.empty[Byte])(bc.encode)).flattenChunks
}

}

object HttpContentCodec {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ private[openapi] object BoolOrSchema {
private[openapi] sealed trait TypeOrTypes { self =>
def add(value: String): TypeOrTypes =
self match {
case TypeOrTypes.Type(string) => TypeOrTypes.Types(Chunk(string, value))
case TypeOrTypes.Types(chunk) => TypeOrTypes.Types(chunk :+ value)
case TypeOrTypes.Type(string) => TypeOrTypes.Types(Chunk(string, value).distinct)
case TypeOrTypes.Types(chunk) => TypeOrTypes.Types((chunk :+ value).distinct)
}
}

Expand Down

0 comments on commit e1afcf2

Please sign in to comment.