Skip to content

Commit

Permalink
Iterate on anorm parsers for scala3 (#703)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbryzek authored Jul 9, 2024
1 parent c383db9 commit 4716b16
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 30 deletions.
13 changes: 12 additions & 1 deletion generator/app/controllers/Generators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,18 @@ object Generators {
attributes = Seq("scala_generator")
),
status = lib.generator.Status.Alpha,
codeGenerator = Some(scala.generator.anorm.ParserGenerator28)
codeGenerator = Some(scala.generator.anorm.ParserGenerator28Scala2)
),
CodeGenTarget(
metaData = Generator(
key = "anorm_2_9_scala_3_parsers",
name = "Anorm 2.9 Scala 3 parsers",
description = Some("Generates anorm parsers. See https://playframework.github.io/anorm/"),
language = Some("Scala"),
attributes = Seq("scala_generator")
),
status = lib.generator.Status.Alpha,
codeGenerator = Some(scala.generator.anorm.ParserGenerator29Scala3)
),
CodeGenTarget(
metaData = Generator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import scala.annotation.nowarn
import lib.Text._

import scala.generator.{ScalaPrimitive, ScalaService}
import scala.models.ScalaVersion

object Conversions {
case class Conversions(scalaVersion: ScalaVersion) {

private val JavaPrimitiveTypes = Seq(
ScalaPrimitive.Boolean,
Expand Down Expand Up @@ -86,24 +87,40 @@ package %s {
private def standard(
types: Seq[ScalaPrimitive],
): String = {
val jsObject = if (scalaVersion.major >= 3) {
Nil
} else {
Seq(s"implicit val columnToJsObject: Column[play.api.libs.json.JsObject] = Util.parser { _.as[play.api.libs.json.JsObject] }")
}
(
Seq(
Seq(
s"implicit val columnToJsObject: Column[play.api.libs.json.JsObject] = Util.parser { _.as[play.api.libs.json.JsObject] }",
jsObject ++ Seq(
s"implicit val columnToJsValue: Column[play.api.libs.json.JsValue] = Util.parser { _.as[play.api.libs.json.JsValue] }"
)
) ++ types.map { t =>
Seq(
s"implicit val columnToSeq${t.shortName}: Column[Seq[${t.fullName}]] = Util.parser { _.as[Seq[${t.fullName}]] }",
s"implicit val columnToMap${t.shortName}: Column[Map[String, ${t.fullName}]] = Util.parser { _.as[Map[String, ${t.fullName}]] }"
)
if (scalaVersion.major >= 3) {
Nil
} else {
Seq(
s"implicit val columnToSeq${t.shortName}: Column[Seq[${t.fullName}]] = Util.parser { _.as[Seq[${t.fullName}]] }",
s"implicit val columnToMap${t.shortName}: Column[Map[String, ${t.fullName}]] = Util.parser { _.as[Map[String, ${t.fullName}]] }"
)
}
}
).flatten.mkString("\n")
}

private case class Name(shortName: String, qualifiedName: String)

private def buildCollectionConversions(ssd: ScalaService): Option[String] = {
if (scalaVersion.major >= 3) {
None
} else {
buildCollectionConversionsScala2(ssd)
}
}

private def buildCollectionConversionsScala2(ssd: ScalaService): Option[String] = {
(
ssd.enums.map(e => Name(e.name, e.qualifiedName)) ++
ssd.models.map(m => Name(m.name, m.qualifiedName)) ++
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scala.generator.anorm

import scala.generator._
import scala.models.{ApiBuilderComments, Attributes, DateTimeTypeConfig, DateTypeConfig}
import scala.models.{ApiBuilderComments, Attributes, DateTimeTypeConfig, DateTypeConfig, ScalaVersion}
import io.apibuilder.generator.v0.models.{File, InvocationForm}
import generator.ServiceFileNames
import lib.generator.CodeGenerator
Expand All @@ -11,6 +11,7 @@ import lib.Text._
import scala.annotation.tailrec

object ParserGenerator24 extends ParserGenerator {
override val version: ScalaVersion = ScalaVersion(2)
override def attributes(ssd: ScalaService): ParserGeneratorPlayVersionSpecificAttributes = ParserGeneratorPlayVersionSpecificAttributes(
imports = Seq(
"anorm.{Column, MetaDataItem, TypeDoesNotMatch}",
Expand All @@ -20,39 +21,58 @@ object ParserGenerator24 extends ParserGenerator {
)
}

object ParserGenerator26 extends ParserGenerator {
object ParserGenerator26 extends AbstractParserGenerator26(ScalaVersion(2))

class AbstractParserGenerator26(override val version: ScalaVersion) extends ParserGenerator {
override def attributes(ssd: ScalaService): ParserGeneratorPlayVersionSpecificAttributes = {
val dateImports = ssd.attributes.dateType match {
case DateTypeConfig.JodaLocalDate => Seq(
"play.api.libs.json.JodaReads._",
)
case _ => Nil
}
val dateTimeImports = ssd.attributes.dateTimeType match {
case DateTimeTypeConfig.JodaDateTime => Seq(
"play.api.libs.json.JodaReads._",
)
case _ => Nil
}
ParserGeneratorPlayVersionSpecificAttributes(
imports = Seq(
"anorm.{Column, MetaDataItem, TypeDoesNotMatch}",
"play.api.libs.json.{JsArray, JsObject, JsValue}",
"scala.util.{Failure, Success, Try}",
) ++ (dateImports ++ dateTimeImports).distinct
baseImports ++ jodaImports(ssd)
)
}

private[this] val baseImports: Seq[String] = {
Seq(
"anorm.{Column, MetaDataItem, TypeDoesNotMatch}",
"play.api.libs.json.{JsArray, JsObject, JsValue}",
"scala.util.{Failure, Success, Try}",
)
}

private[this] def jodaImports(ssd: ScalaService): Seq[String] = {
if (version.major >= 3) {
Nil
} else {
val dateImports = ssd.attributes.dateType match {
case DateTypeConfig.JodaLocalDate => Seq(
"play.api.libs.json.JodaReads._",
)
case _ => Nil
}
val dateTimeImports = ssd.attributes.dateTimeType match {
case DateTimeTypeConfig.JodaDateTime => Seq(
"play.api.libs.json.JodaReads._",
)
case _ => Nil
}
(dateImports ++ dateTimeImports).distinct
}
}
}

object ParserGenerator28 extends ParserGenerator {
object ParserGenerator28Scala2 extends AbstractParserGenerator(ScalaVersion(2))
object ParserGenerator29Scala3 extends AbstractParserGenerator(ScalaVersion(3))
abstract class AbstractParserGenerator(override val version: ScalaVersion) extends ParserGenerator {
override def attributes(ssd: ScalaService): ParserGeneratorPlayVersionSpecificAttributes =
ParserGenerator26.attributes(ssd)
new AbstractParserGenerator26(version).attributes(ssd)
}

case class ParserGeneratorPlayVersionSpecificAttributes(imports: Seq[String])

trait ParserGenerator extends CodeGenerator {

def version: ScalaVersion
private[this] lazy val conversions = Conversions(version)

def attributes(ssd: ScalaService): ParserGeneratorPlayVersionSpecificAttributes

override def invoke(form: InvocationForm): Either[Seq[String], Seq[File]] = {
Expand All @@ -73,7 +93,7 @@ trait ParserGenerator extends CodeGenerator {
form.service.application.key,
form.service.version,
"Conversions",
header ++ Conversions.code(ssd, attributes(ssd)),
header ++ conversions.code(ssd, attributes(ssd)),
Some("Scala")
),
ServiceFileNames.toFile(
Expand Down

0 comments on commit 4716b16

Please sign in to comment.