Skip to content

Commit

Permalink
unify empty arrays to whatever the other array is
Browse files Browse the repository at this point in the history
  • Loading branch information
chadselph committed Mar 26, 2020
1 parent f52f618 commit dfbb910
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 12 deletions.
16 changes: 10 additions & 6 deletions src/main/scala/me/chadrs/json2code/GenerateClass.scala
Expand Up @@ -23,7 +23,8 @@ object GenerateClass {
case object StringType extends JsonTypeTree with CanBeNullable with CanBeInArray with JsonTypeTreeEdge
case object NumericType extends JsonTypeTree with CanBeNullable with CanBeInArray with JsonTypeTreeEdge
case object BooleanType extends JsonTypeTree with CanBeNullable with CanBeInArray with JsonTypeTreeEdge
case object Null extends JsonTypeTree with CanBeInArray with JsonTypeTreeEdge
case object Null extends JsonTypeTree with JsonTypeTreeEdge
case object EmptyArray extends JsonTypeTree
case class NewType(fields: MappedFields) extends JsonTypeTree with CanBeNullable with CanBeInArray
case class ArrayOf(of: CanBeInArray) extends JsonTypeTree

Expand Down Expand Up @@ -52,7 +53,6 @@ object GenerateClass {
case (s, nt: NewType) =>
newTypeParam(s, nt, Type.Name(s.capitalize))

case (s, Null) => simpleParam(s, t"Nothing")
case (s, Nullable(nt: NewType)) =>
val t = Type.Name(s.capitalize)
newTypeParam(s, nt, t"Option[$t]")
Expand All @@ -63,6 +63,9 @@ object GenerateClass {
case (s, ArrayOf(nt: NewType)) =>
val t = Type.Name(s.capitalize)
newTypeParam(s, nt, settings.arrayType(t))
case (s, EmptyArray) =>
val t = t"Nothing"
simpleParam(s, settings.arrayType(t))
}
val params = paramsAndNewTypes.map(_._1)
val newTypes = paramsAndNewTypes.flatMap(_._2)
Expand Down Expand Up @@ -93,8 +96,8 @@ object GenerateClass {
}

def jsonArrayToType(arr: Vector[Json]): Either[String, JsonTypeTree] = {
if(arr.forall(_.isObject)) unifyObjList(arr.map(_.asObject.get)).map(mfs => ArrayOf(NewType(mfs)))
else if (arr.isEmpty) Right(Null)
if (arr.isEmpty) Right(EmptyArray)
else if(arr.forall(_.isObject)) unifyObjList(arr.map(_.asObject.get)).map(mfs => ArrayOf(NewType(mfs)))
else if (isArrayHomogeneous(arr)) jsonTypeToType(arr.head).flatMap {
case canBeInArray: CanBeInArray => Right(ArrayOf(canBeInArray))
case other => Left(s"$other cannot be in an array") // limit what can be in array for sake of simplicity
Expand All @@ -103,7 +106,7 @@ object GenerateClass {
}

def jsonObjToNewType(obj: JsonObject): Either[String, NewType] = {
val keysWithTypes = obj.toMap.toVector.map { case (key, value) => jsonTypeToType(value).map(key -> _) }.sequence
val keysWithTypes = obj.toVector.map { case (key, value) => jsonTypeToType(value).map(key -> _) }.sequence
keysWithTypes.map(NewType)
}

Expand Down Expand Up @@ -148,6 +151,8 @@ object GenerateClass {
case (Null, cbn: CanBeNullable) => Right(Nullable(cbn))
case (cbn: CanBeNullable, Null) => Right(Nullable(cbn))
case (NewType(aFields), NewType(bFields)) => unifyNewTypes(aFields, bFields).map(NewType)
case (EmptyArray, ArrayOf(a)) => Right(ArrayOf(a))
case (ArrayOf(a), EmptyArray) => Right(ArrayOf(a))
// TODO: Arrays?
case _ => Left(s"Can't unify $a and $b yet.")
}
Expand All @@ -173,7 +178,6 @@ object GenerateClass {
packageName: String = "com.test")

// TODO: camelCase snake_case conversion
// TODO: scalajs-ify
// TODO: refactor :|
// TODO: settings for which types get mapped, unify numbers/strings
// TODO: circe encoders / decoders
Expand Down
11 changes: 11 additions & 0 deletions src/test/scala/me/chadrs/json2code/GenerateClassParsingTest.scala
Expand Up @@ -108,6 +108,17 @@ class GenerateClassParsingTest extends org.scalatest.funspec.AnyFunSpec with Mat
"nest3" -> NewType(Vector(
"nest4" -> NumericType)))))))))
}

it("should unify two newtypes when one has an empty array") {
parseJson("objects" -> Json.arr(
Json.obj("projects" -> Json.arr(Json.obj("name" -> Json.fromString("proj1")))),
Json.obj("projects" -> Json.arr())
)) shouldHaveFields(
"objects" -> ArrayOf(NewType(Vector(
"projects" -> ArrayOf(NewType(Vector("name" -> StringType)))
)))
)
}
}

/*
Expand Down
12 changes: 6 additions & 6 deletions src/test/scala/me/chadrs/json2code/TestWIthWeatherApiTest.scala
Expand Up @@ -964,14 +964,14 @@ class TestWIthWeatherApiTest extends AnyFunSpec with Matchers {
.map(input => generate("Response", input))
.fold(_.toString, identity)
result shouldBe """package com.test
|case class Clouds(all: BigDecimal)
|case class Coord(lat: BigDecimal, lon: BigDecimal)
|case class Main(feels_like: BigDecimal, humidity: BigDecimal, pressure: BigDecimal, temp: BigDecimal, temp_max: BigDecimal, temp_min: BigDecimal)
|case class Rain(`1h`: BigDecimal)
|case class Wind(deg: BigDecimal, speed: BigDecimal)
|case class Weather(description: String, icon: String, id: BigDecimal, main: String)
|case class Main(feels_like: BigDecimal, humidity: BigDecimal, temp: BigDecimal, temp_max: BigDecimal, temp_min: BigDecimal, pressure: BigDecimal)
|case class Sys(country: String)
|case class Coord(lat: BigDecimal, lon: BigDecimal)
|case class Clouds(all: BigDecimal)
|case class List(snow: Nothing, name: String, dt: BigDecimal, rain: Option[Rain], wind: Wind, id: BigDecimal, weather: Vector[Weather], main: Main, sys: Sys, coord: Coord, clouds: Clouds)
|case class Weather(description: String, icon: String, id: BigDecimal, main: String)
|case class Wind(deg: BigDecimal, speed: BigDecimal)
|case class List(clouds: Clouds, coord: Coord, dt: BigDecimal, id: BigDecimal, main: Main, name: String, rain: Option[Rain], snow: Nothing, sys: Sys, weather: Vector[Weather], wind: Wind)
|case class Response(cod: String, count: BigDecimal, list: Vector[List], message: String)""".stripMargin


Expand Down

0 comments on commit dfbb910

Please sign in to comment.