Skip to content

Commit 1e3f9be

Browse files
authored
update api scpecs, handle non-unique endpoint locations (#19)
* update api scpecs, handle non-unique endpoint locations * remove accidental commit * update sbt scalafmt * add note * update test
1 parent d90265e commit 1e3f9be

File tree

11 files changed

+49369
-36767
lines changed

11 files changed

+49369
-36767
lines changed

.scalafmt.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version = "3.8.3"
1+
version = "3.10.1"
22
runner.dialect = scala3
33
maxColumn = 120

build.sbt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ val zioVersion = "2.1.22"
4646

4747
val zioJsonVersion = "0.7.45"
4848

49+
// NOTE: update from 2.38.3 to 2.38.4 causes compilation error with some recursive types on codec derivation
4950
val jsoniterVersion = "2.38.2"
5051

5152
val munitVersion = "1.2.1"
@@ -66,7 +67,13 @@ lazy val root = (project in file("."))
6667
// for supporting code inspection / testing of generated code via test_gen.sh script
6768
lazy val testLocal = (project in file("test-local"))
6869
.settings(
69-
libraryDependencies ++= dependencyByConfig("Sttp4", "Jsoniter", "ZioChunk")
70+
libraryDependencies ++= Seq(
71+
"com.softwaremill.sttp.client4" %% "core" % sttpClient4Version,
72+
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % jsoniterVersion,
73+
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % jsoniterVersion % "compile-internal",
74+
"dev.zio" %% "zio-json" % zioJsonVersion,
75+
"dev.zio" %% "zio" % zioVersion
76+
)
7077
)
7178
.settings(noPublish)
7279

modules/cli/src/main/scala/cli.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ private def argsToTask(args: Seq[String]): Either[String, Task] =
7777
jsonCodec = jsonCodec,
7878
preprocess = s => {
7979
incResources.partitionMap(s => if s.startsWith("!") then Left(s.stripPrefix("!")) else Right(s)) match
80-
case (Nil, Nil) => s
81-
case (excl, Nil) => s.copy(resources = s.resources.view.filterKeys(!_.hasMatch(excl)).toMap)
82-
case (Nil, incl) => s.copy(resources = s.resources.view.filterKeys(_.hasMatch(incl)).toMap)
80+
case (Nil, Nil) => s
81+
case (excl, Nil) => s.copy(resources = s.resources.view.filterKeys(!_.hasMatch(excl)).toMap)
82+
case (Nil, incl) => s.copy(resources = s.resources.view.filterKeys(_.hasMatch(incl)).toMap)
8383
case (excl, incl) =>
8484
s.copy(resources = s.resources.view.filterKeys(k => !k.hasMatch(excl) && k.hasMatch(incl)).toMap)
8585
},

modules/core/shared/src/main/scala/codegen.scala

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,18 @@ def generateBySpec(
129129
if specs.endpoints.nonEmpty then "enum Endpoint(val location: String, val url: Uri):" else "",
130130
specs.endpoints
131131
.map(e =>
132+
// for cases where location is not unique we will append numbers
133+
val locationPostfix = specs.endpoints
134+
.collect { case Endpoint(location = e.location, endpointUrl = endpointUrl) =>
135+
endpointUrl
136+
}
137+
.zipWithIndex
138+
.collectFirst { case (e.endpointUrl, idx) if idx > 0 => (idx + 1).toString() }
139+
.getOrElse("")
140+
132141
s"""${toComment(
133142
Some(e.description)
134-
)} case `${e.location}` extends Endpoint("${e.location}", uri"${e.endpointUrl}")""".stripMargin
143+
)} case `${e.location}$locationPostfix` extends Endpoint("${e.location}", uri"${e.endpointUrl}")""".stripMargin
135144
)
136145
.mkString("\n")
137146
).mkString("\n")
@@ -220,7 +229,7 @@ def generateBySpec(
220229
hasProps = p => specs.hasProps(p),
221230
arrType = config.arrayType
222231
) match
223-
case None => Nil
232+
case None => Nil
224233
case Some(codecs) =>
225234
Files.writeString(commonCodecsPath, codecs)
226235
List(commonCodecsPath.toFile())
@@ -301,10 +310,9 @@ def resourceCode(
301310
"\\{(.*?)\\}".r.findAllIn(s).toList match
302311
case Nil => s"PathSegment(\"$s\")"
303312
case v :: Nil if v == s => "PathSegment(" + toScalaName(v.stripPrefix("{").stripSuffix("}")) + ")"
304-
case vars =>
305-
"PathSegment(s\"" + vars.foldLeft(s)((res, v) =>
306-
res.replace(v, "$" + v.stripPrefix("{").stripSuffix("}"))
307-
) + "\")"
313+
case vars =>
314+
"PathSegment(s\"" + vars
315+
.foldLeft(s)((res, v) => res.replace(v, "$" + v.stripPrefix("{").stripSuffix("}"))) + "\")"
308316
)
309317

310318
val req = method.mediaUploads match
@@ -362,15 +370,14 @@ def resourceCode(
362370

363371
val queryParams = "\n val params = " +
364372
(method.scalaQueryParams match
365-
case Nil => "commonQueryParams.value"
373+
case Nil => "commonQueryParams.value"
366374
case qParams =>
367375
qParams
368376
.map {
369377
case (k, p) if p.required => s"""Map("$k" -> $k)"""
370378
case (k, p) => s"""$k.map(p => Map("$k" -> p.toString)).getOrElse(Map.empty)"""
371379
}
372-
.mkString("", " ++ ", " ++ commonQueryParams.value\n")
373-
)
380+
.mkString("", " ++ ", " ++ commonQueryParams.value\n"))
374381

375382
def responseType(t: String) =
376383
httpSource match
@@ -459,7 +466,7 @@ def schemasCode(
459466
s"package $pkg",
460467
"",
461468
jsonCodec match {
462-
case JsonCodec.ZioJson => "import zio.json.*"
469+
case JsonCodec.ZioJson => "import zio.json.*"
463470
case JsonCodec.Jsoniter =>
464471
"""|import com.github.plokhotnyuk.jsoniter_scala.core.*
465472
|import com.github.plokhotnyuk.jsoniter_scala.macros.*""".stripMargin
@@ -492,7 +499,7 @@ def commonSchemaCodecs(
492499
}
493500
)
494501
.distinct match
495-
case Nil => None
502+
case Nil => None
496503
case props =>
497504
Some(
498505
List(
@@ -631,7 +638,7 @@ def readResources(
631638
resources match
632639
case (k, v) :: xs =>
633640
v.obj.remove("resources").map(_.obj) match
634-
case None => readResources(xs, result.updated(k, read[Resource](v)))
641+
case None => readResources(xs, result.updated(k, read[Resource](v)))
635642
case Some(obj) =>
636643
val newRes = obj.map((a, b) => ResourcePath(k, a) -> b).toList ::: xs
637644
Try(read[Resource](v)) match
@@ -727,8 +734,8 @@ enum SchemaType(val optional: Boolean):
727734
case Primitive("number", _, Some("double" | "float")) => toType("Double")
728735
case Primitive("boolean", _, _) => toType("Boolean")
729736
case Ref(ref, _) => toType(ref.scalaName)
730-
case Array(t, _) => toType(arrayType.toScalaType(t.scalaType(arrayType, enumType)))
731-
case Object(t, _) => toType(s"Map[String, ${t.scalaType(arrayType)}]")
737+
case Array(t, _) => toType(arrayType.toScalaType(t.scalaType(arrayType, enumType)))
738+
case Object(t, _) => toType(s"Map[String, ${t.scalaType(arrayType)}]")
732739
case Enum(_, values, _) =>
733740
enumType match
734741
case SchemaType.EnumType.Literal => toType(values.map(v => v.value).mkString("\"", "\" | \"", "\""))
@@ -777,7 +784,7 @@ object SchemaType:
777784
case _ =>
778785
o.value.get("$ref").map(_.str) match
779786
case Some(ref) => SchemaType.Ref(SchemaPath(ref), optional)
780-
case _ =>
787+
case _ =>
781788
if !o.value.keySet.contains("properties") then
782789
if Set("uploadType", "upload_protocol").exists(context.jsonPath.lastOption.contains) then
783790
""""([\w]+)"""".r
@@ -852,7 +859,7 @@ object Schema:
852859
result: Map[SchemaPath, Schema]
853860
): Map[SchemaPath, Schema] =
854861
schemas match {
855-
case Nil => result
862+
case Nil => result
856863
case (name, data) :: xs =>
857864
val schema = readSchema(name, data)
858865

@@ -862,7 +869,7 @@ object Schema:
862869
case None => Nil
863870
case Some(p) => List((p, p.jsonPath.foldLeft(o)(_.apply(_).obj)))
864871
} match {
865-
case Nil => readSchemas(xs, result.updated(name, schema))
872+
case Nil => readSchemas(xs, result.updated(name, schema))
866873
case nested =>
867874
readSchemas(nested ::: xs, result.updated(name, schema))
868875
}
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
package gcp.pubsub.v1.sttp4_jsoniter_ziochunk
22

33
import gcp.pubsub.v1.sttp4_jsoniter_ziochunk.schemas.*
4+
import com.github.plokhotnyuk.jsoniter_scala.core.readFromString
45

56
class PubsubJsoniterCodecSpec extends munit.FunSuite {
6-
test("PublishMessage") {
7+
test("PublishMessage with ordering key") {
78
val pMsg = PubsubMessage(data = Some("data"), attributes = Some(Map("key" -> "value")), orderingKey = Some("key"))
8-
val expected = """{"data":"data","attributes":{"key":"value"},"orderingKey":"key"}"""
9+
val expected = """{"attributes":{"key":"value"},"orderingKey":"key","data":"data"}"""
910
val encoded = pMsg.toJsonString
1011

1112
assert(encoded == expected)
13+
14+
val decoded = readFromString[PubsubMessage](expected)
15+
assert(pMsg == decoded)
1216
}
1317

1418
test("PublishMessage no ordering key") {
1519
val pMsg = PubsubMessage(data = Some("data"), attributes = Some(Map("key" -> "value")))
16-
val expected = """{"data":"data","attributes":{"key":"value"}}"""
20+
val expected = """{"attributes":{"key":"value"},"data":"data"}"""
1721
val encoded = pMsg.toJsonString
1822

1923
assert(encoded == expected)
24+
25+
val decoded = readFromString[PubsubMessage](expected)
26+
assert(pMsg == decoded)
2027
}
2128

2229
test("PublishMessage no ordering key, no attributes") {
@@ -25,5 +32,8 @@ class PubsubJsoniterCodecSpec extends munit.FunSuite {
2532
val encoded = pMsg.toJsonString
2633

2734
assert(encoded == expected)
35+
36+
val decoded = readFromString[PubsubMessage](expected)
37+
assert(pMsg == decoded)
2838
}
2939
}

0 commit comments

Comments
 (0)