Skip to content

Commit

Permalink
support named lists
Browse files Browse the repository at this point in the history
  • Loading branch information
hughsimpson committed Mar 3, 2025
1 parent c4a5d9f commit 69dca11
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ class ClassDefinitionGenerator {
generateClass(allSchemas, name, obj, allTransitiveJsonParamRefs, adtInheritanceMap, jsonSerdeLib, targetScala3)
case (name, obj: OpenapiSchemaEnum) =>
EnumGenerator.generateEnum(name, obj, targetScala3, queryOrPathParamRefs, jsonSerdeLib, allTransitiveJsonParamRefs)
case (name, OpenapiSchemaMap(valueSchema, _)) => generateMap(name, valueSchema)
case (_, _: OpenapiSchemaOneOf) => Nil
case (name, OpenapiSchemaMap(valueSchema, _)) => generateMap(name, valueSchema)
case (name, OpenapiSchemaArray(valueSchema, _)) => generateArray(name, valueSchema)
case (_, _: OpenapiSchemaOneOf) => Nil
case (n, x) => throw new NotImplementedError(s"Only objects, enums and maps supported! (for $n found ${x})")
})
.map(_.mkString("\n"))
Expand Down Expand Up @@ -207,6 +208,17 @@ class ClassDefinitionGenerator {
Seq(s"""type $name = Map[String, $valueSchemaName]""")
}

private[codegen] def generateArray(
name: String,
valueSchema: OpenapiSchemaType
): Seq[String] = {
val valueSchemaName = valueSchema match {
case simpleType: OpenapiSchemaSimpleType => BasicGenerator.mapSchemaSimpleTypeToType(simpleType)._1
case otherType => throw new NotImplementedError(s"Only simple value types and refs are implemented for named maps (found $otherType)")
}
Seq(s"""type $name = List[$valueSchemaName]""")
}

private[codegen] def generateClass(
allSchemas: Map[String, OpenapiSchemaType],
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ object JsonSerdeGenerator {
case (name, schema: OpenapiSchemaObject) if allTransitiveJsonParamRefs.contains(name) =>
Some(genCirceObjectSerde(name, schema))
case (name, schema: OpenapiSchemaMap) if allTransitiveJsonParamRefs.contains(name) =>
Some(genCirceMapSerde(name, schema))
Some(genCirceMapOrArraySerde(name, schema.items))
case (name, schema: OpenapiSchemaArray) if allTransitiveJsonParamRefs.contains(name) =>
Some(genCirceMapOrArraySerde(name, schema.items))
case (name, schema: OpenapiSchemaOneOf) if allTransitiveJsonParamRefs.contains(name) =>
Some(genCirceAdtSerde(allSchemas, schema, name, validateNonDiscriminatedOneOfs))
case (_, _: OpenapiSchemaObject | _: OpenapiSchemaMap | _: OpenapiSchemaEnum | _: OpenapiSchemaOneOf | _: OpenapiSchemaAny) => None
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps and oneOf supported! (for $n found ${x})")
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps, arrays and oneOf supported! (for $n found ${x})")
})
.map(_.mkString("\n"))
}
Expand All @@ -149,8 +151,8 @@ object JsonSerdeGenerator {
s"""${subs}implicit lazy val ${uncapitalisedName}JsonDecoder: io.circe.Decoder[$name] = io.circe.generic.semiauto.deriveDecoder[$name]
|implicit lazy val ${uncapitalisedName}JsonEncoder: io.circe.Encoder[$name] = io.circe.generic.semiauto.deriveEncoder[$name]""".stripMargin
}
private def genCirceMapSerde(name: String, schema: OpenapiSchemaMap): String = {
val subs = schema.items match {
private def genCirceMapOrArraySerde(name: String, schema: OpenapiSchemaType): String = {
val subs = schema match {
case `type`: OpenapiSchemaObject => Some(genCirceObjectSerde(s"${name}ObjectsItem", `type`))
case _ => None
}
Expand Down Expand Up @@ -271,7 +273,7 @@ object JsonSerdeGenerator {
adtInheritanceMap.get(name).getOrElse(Nil).map(allSchemas.apply).collect { case oneOf: OpenapiSchemaOneOf => oneOf }
if (jsonParamRefs.contains(name) || supertypes.exists(_.discriminator.isEmpty)) Some(genJsoniterClassSerde(supertypes)(name))
else None
// For named maps, only generate the schema if it's a 'top level' json schema
// For named maps or seqs, only generate the schema if it's a 'top level' json schema
case (name, _: OpenapiSchemaMap) if jsonParamRefs.contains(name) =>
Some(genJsoniterNamedSerde(name))
// For enums, generate the serde if it's referenced in any json model
Expand All @@ -280,8 +282,13 @@ object JsonSerdeGenerator {
// For ADTs, generate the serde if it's referenced in any json model
case (name, schema: OpenapiSchemaOneOf) if allTransitiveJsonParamRefs.contains(name) =>
Some(generateJsoniterAdtSerde(allSchemas, name, schema, validateNonDiscriminatedOneOfs))
case (_, _: OpenapiSchemaObject | _: OpenapiSchemaMap | _: OpenapiSchemaEnum | _: OpenapiSchemaOneOf | _: OpenapiSchemaAny) => None
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps and oneOf supported! (for $n found ${x})")
case (
_,
_: OpenapiSchemaObject | _: OpenapiSchemaMap | _: OpenapiSchemaArray | _: OpenapiSchemaEnum | _: OpenapiSchemaOneOf |
_: OpenapiSchemaAny
) =>
None
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps, arrays and oneOf supported! (for $n found ${x})")
})
.map(jsonSerdeHelpers + additionalExplicitSerdes + _.mkString("\n"))
}
Expand Down Expand Up @@ -396,11 +403,14 @@ object JsonSerdeGenerator {
case (name, schema: OpenapiSchemaObject) if allTransitiveJsonParamRefs.contains(name) =>
Some(genZioObjectSerde(name, schema))
case (name, schema: OpenapiSchemaMap) if allTransitiveJsonParamRefs.contains(name) =>
Some(genZioMapSerde(name, schema))
Some(genZioMapOrArraySerde(name, schema.items))
case (name, schema: OpenapiSchemaArray) if allTransitiveJsonParamRefs.contains(name) =>
Some(genZioMapOrArraySerde(name, schema.items))
case (name, schema: OpenapiSchemaOneOf) if allTransitiveJsonParamRefs.contains(name) =>
Some(genZioAdtSerde(allSchemas, schema, name, validateNonDiscriminatedOneOfs))
case (_, _: OpenapiSchemaObject | _: OpenapiSchemaMap | _: OpenapiSchemaEnum | _: OpenapiSchemaOneOf) => None
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps and oneOf supported! (for $n found ${x})")
case (_, _: OpenapiSchemaObject | _: OpenapiSchemaMap | _: OpenapiSchemaArray | _: OpenapiSchemaEnum | _: OpenapiSchemaOneOf) =>
None
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps, arrays and oneOf supported! (for $n found ${x})")
})
.map(_.mkString("\n"))
}
Expand All @@ -421,8 +431,8 @@ object JsonSerdeGenerator {
|implicit lazy val ${uncapitalisedName}JsonEncoder: zio.json.JsonEncoder[$name] = zio.json.DeriveJsonEncoder.gen[$name]""".stripMargin
}

private def genZioMapSerde(name: String, schema: OpenapiSchemaMap): String = {
val subs = schema.items match {
private def genZioMapOrArraySerde(name: String, schema: OpenapiSchemaType): String = {
val subs = schema match {
case `type`: OpenapiSchemaObject => Some(genZioObjectSerde(s"${name}ObjectsItem", `type`))
case _ => None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ object SchemaGenerator {
Some(
name -> s"implicit lazy val ${BasicGenerator.uncapitalise(name)}TapirSchema: sttp.tapir.Schema[$name] = sttp.tapir.Schema.derived"
)
case (name, obj: OpenapiSchemaObject) => Some(name -> schemaForObject(name, obj))
case (name, schema: OpenapiSchemaMap) => Some(name -> schemaForMap(name, schema))
case (_, _: OpenapiSchemaAny) => None
case (name, obj: OpenapiSchemaObject) => Some(name -> schemaForObject(name, obj))
case (name, schema: OpenapiSchemaMap) => Some(name -> schemaForMapOrArray(name, schema.items))
case (name, schema: OpenapiSchemaArray) => Some(name -> schemaForMapOrArray(name, schema.items))
case (_, _: OpenapiSchemaAny) => None
case (name, schema: OpenapiSchemaOneOf) =>
Some(name -> genADTSchema(name, schema, if (fullModelPath.isEmpty) None else Some(fullModelPath)))
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps and oneOf supported! (for $n found ${x})")
case (n, x) => throw new NotImplementedError(s"Only objects, enums, maps, arrays and oneOf supported! (for $n found ${x})")
})
.toSeq
.flatMap(maybeAnySchema.toSeq ++ _)
Expand Down Expand Up @@ -197,8 +198,8 @@ object SchemaGenerator {
}
s"${subs}implicit lazy val ${BasicGenerator.uncapitalise(name)}TapirSchema: sttp.tapir.Schema[$name] = sttp.tapir.Schema.derived"
}
private def schemaForMap(name: String, schema: OpenapiSchemaMap): String = {
val subs = schema.items match {
private def schemaForMapOrArray(name: String, schema: OpenapiSchemaType): String = {
val subs = schema match {
case `type`: OpenapiSchemaObject => Some(schemaForObject(s"${name}ObjectsItem", `type`))
case _ => None
}
Expand Down

0 comments on commit 69dca11

Please sign in to comment.