Skip to content

Commit

Permalink
Add ConfigValueReader(s) for PulumiEnum(s)
Browse files Browse the repository at this point in the history
- add stringEnumReader,
booleanEnumReader,
intEnumReader, doubleEnumReader to ConfigValueReader
  • Loading branch information
pawelprazak committed Dec 15, 2023
1 parent 5fca170 commit e70d207
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 13 deletions.
8 changes: 6 additions & 2 deletions codegen/src/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ class CodeGen(implicit
pulumiPackage.parsedTypes.flatMap { case (coordinates, typeDefinition) =>
typeDefinition match {
case enumDef: EnumTypeDefinition =>
sourceFilesForEnum(typeCoordinates = coordinates, enumDefinition = enumDef)
sourceFilesForEnum(
typeCoordinates = coordinates,
enumDefinition = enumDef
)
case objectDef: ObjectTypeDefinition =>
sourceFilesForObjectType(
typeCoordinates = coordinates,
Expand All @@ -144,7 +147,7 @@ class CodeGen(implicit
): Seq[SourceFile] = {
val classCoordinates = typeCoordinates.asEnumClass

val enumClassName = classCoordinates.definitionTermName.getOrElse(
val enumClassName = classCoordinates.definitionTypeName.getOrElse(
throw GeneralCodegenException(
s"Class name for ${classCoordinates.typeRef} could not be found"
)
Expand Down Expand Up @@ -191,6 +194,7 @@ class CodeGen(implicit
| override val allInstances: Seq[${enumClassName}] = Seq(
|${instances.map(instance => s" ${instance._2.syntax}").mkString(",\n")}
| )
| given besom.types.EnumCompanion[${valueType}, ${enumClassName}] = this
|""".stripMargin.parse[Source].get

Seq(
Expand Down
2 changes: 2 additions & 0 deletions codegen/src/CodeGen.test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ class CodeGenTest extends munit.FunSuite {
| SupplementalServicing,
| PremiumAssurance
| )
| given besom.types.EnumCompanion[String, SupportType] = this
|""".stripMargin,
"src/windowsesu/MultipleActivationKeyArgs.scala" ->
"""|package besom.api.azurenative.windowsesu
Expand Down Expand Up @@ -459,6 +460,7 @@ class CodeGenTest extends munit.FunSuite {
| NotRequired,
| Required
| )
| given besom.types.EnumCompanion[String, UserConfirmation] = this
|""".stripMargin,
"src/hybriddata/JobDefinitionArgs.scala" ->
"""|package besom.api.azurenative.hybriddata
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/scala/besom/internal/ConfigValueReader.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package besom.internal

import besom.types.{BooleanEnum, EnumCompanion, IntegerEnum, NumberEnum, StringEnum}
import spray.json.*

import scala.util.Try
Expand All @@ -23,6 +24,14 @@ object ConfigValueReader:
given jsonReader: ConfigValueReader[JsValue] with
override def read(key: String, rawValue: String): Either[Exception, JsValue] =
Try(rawValue.parseJson).toEither.left.map(e => ConfigError(s"Config value '$key' is not a valid JSON: $rawValue", e))
given stringEnumReader[E <: StringEnum, C <: EnumCompanion[String, E]](using ec: C): ConfigValueReader[E] with
override def read(key: String, rawValue: String): Either[Exception, E] = ec.fromValue(rawValue)
given booleanEnumReader[E <: BooleanEnum, C <: EnumCompanion[Boolean, E]](using ec: C): ConfigValueReader[E] with
override def read(key: String, rawValue: String): Either[Exception, E] = ec.fromValue(rawValue.toBoolean)
given intEnumReader[E <: IntegerEnum, C <: EnumCompanion[Int, E]](using ec: C): ConfigValueReader[E] with
override def read(key: String, rawValue: String): Either[Exception, E] = ec.fromValue(rawValue.toInt)
given doubleEnumReader[E <: NumberEnum, C <: EnumCompanion[Double, E]](using ec: C): ConfigValueReader[E] with
override def read(key: String, rawValue: String): Either[Exception, E] = ec.fromValue(rawValue.toDouble)
given objectReader[A: JsonReader]: ConfigValueReader[A] with
override def read(key: String, rawValue: String): Either[Exception, A] =
Try(rawValue.parseJson.convertTo[A]).toEither.left.map(e =>
Expand Down
15 changes: 10 additions & 5 deletions core/src/main/scala/besom/types.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package besom

import besom.internal.*
import besom.internal.ProtobufUtil.*
import besom.util.*
import com.google.protobuf.struct.*

import scala.compiletime.*
import scala.compiletime.ops.string.*
import scala.language.implicitConversions
import scala.util.Try
import com.google.protobuf.struct.*
import besom.internal.ProtobufUtil.*
import besom.util.*
import besom.internal.*

object types:
// TODO: replace these stubs with proper implementations
Expand Down Expand Up @@ -328,7 +329,11 @@ object types:

trait EnumCompanion[V, E <: PulumiEnum[V]](enumName: String):
def allInstances: Seq[E]
private lazy val valuesToInstances: Map[Any, E] = allInstances.map(instance => instance.value -> instance).toMap
def fromValue(value: V): Either[Exception, E] = valuesToInstances.get(value).toRight(
left = Exception(s"`${value}` is not a valid value of `${enumName}`")
)

private lazy val valuesToInstances: Map[V, E] = allInstances.map(instance => instance.value -> instance).toMap

extension [A](a: A)
def asValueAny: Value = a match
Expand Down
63 changes: 57 additions & 6 deletions core/src/test/scala/besom/internal/ConfigTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,59 @@ class ConfigTest extends munit.FunSuite {
assertEquals(actual, expected)
}

sealed abstract class Region(val name: String, val value: String) extends besom.types.StringEnum
object Region extends EnumCompanion[String, Region]("Region"):
object AFSouth1 extends Region("AFSouth1", "af-south-1")
object APEast1 extends Region("APEast1", "ap-east-1")
object APNortheast1 extends Region("APNortheast1", "ap-northeast-1")
object APNortheast2 extends Region("APNortheast2", "ap-northeast-2")
override val allInstances: Seq[Region] = Seq(
AFSouth1,
APEast1,
APNortheast1,
APNortheast2
)
given EnumCompanion[String, Region] = this

testConfig("get StringEnum")(
configMap = Map("prov:region" -> "ap-northeast-1"),
configSecretKeys = Set.empty,
tested = Codegen.config[Region]("prov")(
key = "region",
isSecret = false,
environment = Nil,
default = None
)
) { actual =>
val expected = OutputData(Some(Region.APNortheast1))
assertEquals(actual, expected)
}


sealed abstract class Switch(val name: String, val value: Boolean) extends besom.types.BooleanEnum
object Switch extends EnumCompanion[Boolean, Switch]("Switch"):
object On extends Switch("On", true)
object Off extends Switch("Off", false)
override val allInstances: Seq[Switch] = Seq(On, Off)
given EnumCompanion[Boolean, Switch] = this

testConfig("get BooleanEnum")(
configMap = Map("prov:switch" -> "false"),
configSecretKeys = Set.empty,
tested = Codegen.config[Switch]("prov")(
key = "switch",
isSecret = false,
environment = Nil,
default = None
)
) { actual =>
val expected = OutputData(Some(Switch.Off))
assertEquals(actual, expected)
}

case class Foo(a: Int, b: Int)
given JsonFormat[Foo] = jsonFormat2(Foo.apply)
object Foo:
given JsonFormat[Foo] = jsonFormat2(Foo.apply)
testConfig("get case class Foo")(
configMap = Map("foo" -> """{"a":1,"b":2}"""),
configSecretKeys = Set("foo"),
Expand All @@ -170,7 +221,7 @@ class ConfigTest extends munit.FunSuite {
case class Bar(a: Int, b: Int)
testConfig("get case class Bar compile error")(
configMap = Map("bar" -> """{"a":1,"b":2}"""),
configSecretKeys = Set.empty,
configSecretKeys = Set.empty
) {
assertNoDiff(
compileErrors("""config.getObject[Bar]("bar")"""),
Expand All @@ -190,7 +241,7 @@ class ConfigTest extends munit.FunSuite {

testConfig("require case Bar class compile error")(
configMap = Map("bar" -> """{"a":1,"b":2}"""),
configSecretKeys = Set.empty,
configSecretKeys = Set.empty
) {
assertNoDiff(
compileErrors("""config.requireObject[Bar]("bar")"""),
Expand Down Expand Up @@ -262,7 +313,7 @@ class ConfigTest extends munit.FunSuite {
assertEquals(outputData2, OutputData(Some("bar")))
}

testConfig("Codegen.config") (
testConfig("Codegen.config - List")(
configMap = Map("prov:names" -> """["a","b","c","super secret name"]"""),
configSecretKeys = Set.empty,
tested = Codegen.config[List[String]]("prov")(
Expand All @@ -272,7 +323,7 @@ class ConfigTest extends munit.FunSuite {
default = None
)
) { actual =>
val expected = OutputData(Some(List("a", "b", "c", "super secret name")), isSecret = true)
assertEquals(actual, expected)
val expected = OutputData(Some(List("a", "b", "c", "super secret name")), isSecret = true)
assertEquals(actual, expected)
}
}

0 comments on commit e70d207

Please sign in to comment.