Skip to content

Commit c4c8ecc

Browse files
committed
Fix exhaustive matching
1 parent f8581d1 commit c4c8ecc

File tree

6 files changed

+150
-106
lines changed

6 files changed

+150
-106
lines changed

zio-http-cli/src/main/scala/zio/http/endpoint/cli/HttpOptions.scala

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package zio.http.endpoint.cli
22

3+
import scala.annotation.tailrec
34
import scala.language.implicitConversions
45
import scala.util.Try
56

@@ -310,9 +311,10 @@ private[cli] object HttpOptions {
310311
}
311312

312313
private[cli] def optionsFromSegment(segment: SegmentCodec[_]): Options[String] = {
314+
@tailrec
313315
def fromSegment[A](segment: SegmentCodec[A]): Options[String] =
314316
segment match {
315-
case SegmentCodec.UUID(name) =>
317+
case SegmentCodec.UUID(name) =>
316318
Options
317319
.text(name)
318320
.mapOrFail(str =>
@@ -324,13 +326,14 @@ private[cli] object HttpOptions {
324326
},
325327
)
326328
.map(_.toString)
327-
case SegmentCodec.Text(name) => Options.text(name)
328-
case SegmentCodec.IntSeg(name) => Options.integer(name).map(_.toInt).map(_.toString)
329-
case SegmentCodec.LongSeg(name) => Options.integer(name).map(_.toInt).map(_.toString)
330-
case SegmentCodec.BoolSeg(name) => Options.boolean(name).map(_.toString)
331-
case SegmentCodec.Literal(value) => Options.Empty.map(_ => value)
332-
case SegmentCodec.Trailing => Options.none.map(_.toString)
333-
case SegmentCodec.Empty => Options.none.map(_.toString)
329+
case SegmentCodec.Text(name) => Options.text(name)
330+
case SegmentCodec.IntSeg(name) => Options.integer(name).map(_.toInt).map(_.toString)
331+
case SegmentCodec.LongSeg(name) => Options.integer(name).map(_.toInt).map(_.toString)
332+
case SegmentCodec.BoolSeg(name) => Options.boolean(name).map(_.toString)
333+
case SegmentCodec.Literal(value) => Options.Empty.map(_ => value)
334+
case SegmentCodec.Trailing => Options.none.map(_.toString)
335+
case SegmentCodec.Empty => Options.none.map(_.toString)
336+
case SegmentCodec.Annotated(codec, _) => fromSegment(codec)
334337
}
335338

336339
fromSegment(segment)

zio-http-cli/src/test/scala/zio/http/endpoint/cli/CommandGen.scala

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package zio.http.endpoint.cli
22

3+
import scala.annotation.tailrec
4+
35
import zio.cli._
46
import zio.test._
57

@@ -18,17 +20,20 @@ import zio.http.endpoint.cli.EndpointGen._
1820
object CommandGen {
1921

2022
def getSegment(segment: SegmentCodec[_]): (String, String) = {
23+
@tailrec
2124
def fromSegment[A](segment: SegmentCodec[A]): (String, String) =
2225
segment match {
23-
case SegmentCodec.UUID(name) => (name, "text")
24-
case SegmentCodec.Text(name) => (name, "text")
25-
case SegmentCodec.IntSeg(name) => (name, "integer")
26-
case SegmentCodec.LongSeg(name) => (name, "integer")
27-
case SegmentCodec.BoolSeg(name) => (name, "boolean")
28-
case SegmentCodec.Literal(_) => ("", "")
29-
case SegmentCodec.Trailing => ("", "")
30-
case SegmentCodec.Empty => ("", "")
26+
case SegmentCodec.UUID(name) => (name, "text")
27+
case SegmentCodec.Text(name) => (name, "text")
28+
case SegmentCodec.IntSeg(name) => (name, "integer")
29+
case SegmentCodec.LongSeg(name) => (name, "integer")
30+
case SegmentCodec.BoolSeg(name) => (name, "boolean")
31+
case SegmentCodec.Literal(_) => ("", "")
32+
case SegmentCodec.Trailing => ("", "")
33+
case SegmentCodec.Empty => ("", "")
34+
case SegmentCodec.Annotated(codec, _) => fromSegment(codec)
3135
}
36+
3237
fromSegment(segment)
3338
}
3439

zio-http/src/main/scala/zio/http/codec/PathCodec.scala

+13-12
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616

1717
package zio.http.codec
1818

19-
import scala.annotation.tailrec
2019
import scala.collection.immutable.ListMap
2120
import scala.language.implicitConversions
2221

23-
import zio.stacktracer.TracingImplicits.disableAutoTrace
24-
import zio.{Chunk, NonEmptyChunk}
22+
import zio._
2523

2624
import zio.http.Path
2725

@@ -266,14 +264,15 @@ sealed trait PathCodec[A] { self =>
266264
pattern match {
267265
case PathCodec.Segment(segment) =>
268266
Chunk(segment.asInstanceOf[SegmentCodec[_]] match {
269-
case SegmentCodec.Empty => Opt.Unit
270-
case SegmentCodec.Literal(value) => Opt.Match(value)
271-
case SegmentCodec.IntSeg(_) => Opt.IntOpt
272-
case SegmentCodec.LongSeg(_) => Opt.LongOpt
273-
case SegmentCodec.Text(_) => Opt.StringOpt
274-
case SegmentCodec.UUID(_) => Opt.UUIDOpt
275-
case SegmentCodec.BoolSeg(_) => Opt.BoolOpt
276-
case SegmentCodec.Trailing => Opt.TrailingOpt
267+
case SegmentCodec.Empty => Opt.Unit
268+
case SegmentCodec.Literal(value) => Opt.Match(value)
269+
case SegmentCodec.IntSeg(_) => Opt.IntOpt
270+
case SegmentCodec.LongSeg(_) => Opt.LongOpt
271+
case SegmentCodec.Text(_) => Opt.StringOpt
272+
case SegmentCodec.UUID(_) => Opt.UUIDOpt
273+
case SegmentCodec.BoolSeg(_) => Opt.BoolOpt
274+
case SegmentCodec.Trailing => Opt.TrailingOpt
275+
case SegmentCodec.Annotated(codec, _) => loop(PathCodec.Segment(codec)).head
277276
})
278277

279278
case Concat(left, right, combiner, _) =>
@@ -305,14 +304,16 @@ sealed trait PathCodec[A] { self =>
305304
loop(self)
306305
}
307306

308-
def renderIgnoreTrailing: String = {
307+
private[zio] def renderIgnoreTrailing: String = {
309308
def loop(path: PathCodec[_]): String = path match {
310309
case PathCodec.Concat(left, right, _, _) =>
311310
loop(left) + loop(right)
312311

313312
case PathCodec.Segment(SegmentCodec.Trailing) => ""
314313

315314
case PathCodec.Segment(segment) => segment.render
315+
316+
case PathCodec.TransformOrFail(api, _, _) => loop(api)
316317
}
317318

318319
loop(self)

zio-http/src/main/scala/zio/http/endpoint/openapi/JsonSchema.scala

+30-5
Original file line numberDiff line numberDiff line change
@@ -292,22 +292,47 @@ object JsonSchema {
292292
case TextCodec.Constant(string) => JsonSchema.Enum(Chunk(EnumValue.Str(string)))
293293
case TextCodec.StringCodec => JsonSchema.String
294294
case TextCodec.IntCodec => JsonSchema.Integer(JsonSchema.IntegerFormat.Int32)
295+
case TextCodec.LongCodec => JsonSchema.Integer(JsonSchema.IntegerFormat.Int64)
295296
case TextCodec.BooleanCodec => JsonSchema.Boolean
296297
case TextCodec.UUIDCodec => JsonSchema.String
297298
}
298299

299300
def fromSegmentCodec(codec: SegmentCodec[_]): JsonSchema =
300301
codec match {
301-
case SegmentCodec.BoolSeg(_) => JsonSchema.Boolean
302-
case SegmentCodec.IntSeg(_) => JsonSchema.Integer(JsonSchema.IntegerFormat.Int32)
303-
case SegmentCodec.LongSeg(_) => JsonSchema.Integer(JsonSchema.IntegerFormat.Int64)
304-
case SegmentCodec.Text(_) => JsonSchema.String
305-
case SegmentCodec.UUID(_) => JsonSchema.String
302+
case SegmentCodec.BoolSeg(_) => JsonSchema.Boolean
303+
case SegmentCodec.IntSeg(_) => JsonSchema.Integer(JsonSchema.IntegerFormat.Int32)
304+
case SegmentCodec.LongSeg(_) => JsonSchema.Integer(JsonSchema.IntegerFormat.Int64)
305+
case SegmentCodec.Text(_) => JsonSchema.String
306+
case SegmentCodec.UUID(_) => JsonSchema.String
307+
case SegmentCodec.Annotated(codec, annotations) =>
308+
fromSegmentCodec(codec).description(segmentDoc(annotations)).examples(segmentExamples(codec, annotations))
306309
case SegmentCodec.Literal(_) => throw new IllegalArgumentException("Literal segment is not supported.")
307310
case SegmentCodec.Empty => throw new IllegalArgumentException("Empty segment is not supported.")
308311
case SegmentCodec.Trailing => throw new IllegalArgumentException("Trailing segment is not supported.")
309312
}
310313

314+
private def segmentDoc(annotations: Chunk[SegmentCodec.MetaData[_]]) =
315+
annotations.collect { case SegmentCodec.MetaData.Documented(doc) => doc }.reduceOption(_ + _).map(_.toCommonMark)
316+
317+
private def segmentExamples(codec: SegmentCodec[_], annotations: Chunk[SegmentCodec.MetaData[_]]) =
318+
Chunk.fromIterable(
319+
annotations.collect { case SegmentCodec.MetaData.Examples(example) => example.values }.flatten.map { value =>
320+
codec match {
321+
case SegmentCodec.Empty => throw new IllegalArgumentException("Empty segment is not supported.")
322+
case SegmentCodec.Literal(_) => throw new IllegalArgumentException("Literal segment is not supported.")
323+
case SegmentCodec.BoolSeg(_) => Json.Bool(value.asInstanceOf[Boolean])
324+
case SegmentCodec.IntSeg(_) => Json.Num(value.asInstanceOf[Int])
325+
case SegmentCodec.LongSeg(_) => Json.Num(value.asInstanceOf[Long])
326+
case SegmentCodec.Text(_) => Json.Str(value.asInstanceOf[String])
327+
case SegmentCodec.UUID(_) => Json.Str(value.asInstanceOf[java.util.UUID].toString)
328+
case SegmentCodec.Trailing =>
329+
throw new IllegalArgumentException("Trailing segment is not supported.")
330+
case SegmentCodec.Annotated(_, _) =>
331+
throw new IllegalStateException("Annotated SegmentCodec should never be nested.")
332+
}
333+
},
334+
)
335+
311336
def fromZSchema(schema: Schema[_], refType: SchemaStyle = SchemaStyle.Inline): JsonSchema =
312337
schema match {
313338
case enum0: Schema.Enum[_] if refType != SchemaStyle.Inline && nominal(enum0).isDefined =>

zio-http/src/main/scala/zio/http/endpoint/openapi/OpenAPI.scala

+41-41
Original file line numberDiff line numberDiff line change
@@ -445,21 +445,21 @@ object OpenAPI {
445445
* path.
446446
* @param description
447447
* A description, intended to apply to all operations in this path.
448-
* @param getOp
448+
* @param get
449449
* A definition of a GET operation on this path.
450-
* @param putOp
450+
* @param put
451451
* A definition of a PUT operation on this path.
452-
* @param postOp
452+
* @param post
453453
* A definition of a POST operation on this path.
454-
* @param deleteOp
454+
* @param delete
455455
* A definition of a DELETE operation on this path.
456-
* @param optionsOp
456+
* @param options
457457
* A definition of a OPTIONS operation on this path.
458-
* @param headOp
458+
* @param head
459459
* A definition of a HEAD operation on this path.
460-
* @param patchOp
460+
* @param patch
461461
* A definition of a PATCH operation on this path.
462-
* @param traceOp
462+
* @param trace
463463
* A definition of a TRACE operation on this path.
464464
* @param servers
465465
* An alternative server List to service all operations in this path.
@@ -474,35 +474,35 @@ object OpenAPI {
474474
@fieldName("$ref") ref: Option[String],
475475
summary: Option[String],
476476
description: Option[Doc],
477-
getOp: Option[Operation],
478-
putOp: Option[Operation],
479-
postOp: Option[Operation],
480-
deleteOp: Option[Operation],
481-
optionsOp: Option[Operation],
482-
headOp: Option[Operation],
483-
patchOp: Option[Operation],
484-
traceOp: Option[Operation],
477+
get: Option[Operation],
478+
put: Option[Operation],
479+
post: Option[Operation],
480+
delete: Option[Operation],
481+
options: Option[Operation],
482+
head: Option[Operation],
483+
patch: Option[Operation],
484+
trace: Option[Operation],
485485
servers: List[Server] = List.empty,
486486
parameters: Set[ReferenceOr[Parameter]] = Set.empty,
487487
) {
488-
def get(operation: Operation): PathItem = copy(getOp = Some(operation))
489-
def put(operation: Operation): PathItem = copy(putOp = Some(operation))
490-
def post(operation: Operation): PathItem = copy(postOp = Some(operation))
491-
def delete(operation: Operation): PathItem = copy(deleteOp = Some(operation))
492-
def options(operation: Operation): PathItem = copy(optionsOp = Some(operation))
493-
def head(operation: Operation): PathItem = copy(headOp = Some(operation))
494-
def patch(operation: Operation): PathItem = copy(patchOp = Some(operation))
495-
def trace(operation: Operation): PathItem = copy(traceOp = Some(operation))
496-
def any(operation: Operation): PathItem =
488+
def addGet(operation: Operation): PathItem = copy(get = Some(operation))
489+
def addPut(operation: Operation): PathItem = copy(put = Some(operation))
490+
def addPost(operation: Operation): PathItem = copy(post = Some(operation))
491+
def addDelete(operation: Operation): PathItem = copy(delete = Some(operation))
492+
def addOptions(operation: Operation): PathItem = copy(options = Some(operation))
493+
def addHead(operation: Operation): PathItem = copy(head = Some(operation))
494+
def addPatch(operation: Operation): PathItem = copy(patch = Some(operation))
495+
def addTrace(operation: Operation): PathItem = copy(trace = Some(operation))
496+
def any(operation: Operation): PathItem =
497497
copy(
498-
getOp = Some(operation),
499-
putOp = Some(operation),
500-
postOp = Some(operation),
501-
deleteOp = Some(operation),
502-
optionsOp = Some(operation),
503-
headOp = Some(operation),
504-
patchOp = Some(operation),
505-
traceOp = Some(operation),
498+
get = Some(operation),
499+
put = Some(operation),
500+
post = Some(operation),
501+
delete = Some(operation),
502+
options = Some(operation),
503+
head = Some(operation),
504+
patch = Some(operation),
505+
trace = Some(operation),
506506
)
507507
}
508508

@@ -514,14 +514,14 @@ object OpenAPI {
514514
ref = None,
515515
summary = None,
516516
description = None,
517-
getOp = None,
518-
putOp = None,
519-
postOp = None,
520-
deleteOp = None,
521-
optionsOp = None,
522-
headOp = None,
523-
patchOp = None,
524-
traceOp = None,
517+
get = None,
518+
put = None,
519+
post = None,
520+
delete = None,
521+
options = None,
522+
head = None,
523+
patch = None,
524+
trace = None,
525525
servers = List.empty,
526526
parameters = Set.empty,
527527
)

0 commit comments

Comments
 (0)