Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use zio.Config.Switch for discriminated sum types #1167

Merged
merged 9 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
fail-fast: false
matrix:
java: ['adopt@1.8', 'adopt@1.11']
scala: ['2.11.12', '2.12.16', '2.13.8', '3.2.2']
scala: ['2.12.16', '2.13.8', '3.2.2']
platform: ['JS', 'JVM', 'Native']
steps:
- name: Checkout current branch
Expand Down
31 changes: 7 additions & 24 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@ addCommandAlias(
)
addCommandAlias(
"testJVM3x",
";zioConfigJVM/test;zioConfigTypesafeJVM/test;zioConfigDerivationJVM/test;zioConfigYamlJVM/test;zioConfigAwsJVM/test;zioConfigZioAwsJVM/test;zioConfigXmlJVM/test"
";zioConfigJVM/test;zioConfigTypesafeJVM/test;zioConfigDerivationJVM/test;zioConfigYamlJVM/test;zioConfigMagnoliaJVM/test;zioConfigAwsJVM/test;zioConfigZioAwsJVM/test;zioConfigXmlJVM/test"
)

val awsVersion = "1.12.360"
val zioAwsVersion = "5.19.33.2"
val zioVersion = "2.0.10"
val zioVersion = "2.0.13"
val magnoliaVersion = "0.17.0"
val refinedVersion = "0.10.3"
val pureconfigVersion = "0.16.0"
val shapelessVersion = "2.4.0-M1"

lazy val magnoliaDependencies =
libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.11" || scalaVersion.value == ScalaDotty) Seq.empty // Just to make IntelliJ happy
if (scalaVersion.value == ScalaDotty) Seq.empty // Just to make IntelliJ happy
else {
Seq(
"com.propensive" %% "magnolia" % magnoliaVersion,
Expand All @@ -64,14 +64,11 @@ lazy val magnoliaDependencies =
}

lazy val refinedDependencies =
libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.11") Seq.empty // Just to make IntelliJ happy
else Seq("eu.timepit" %% "refined" % refinedVersion)
}
libraryDependencies ++= Seq("eu.timepit" %% "refined" % refinedVersion)

lazy val pureconfigDependencies =
libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.11" || scalaVersion.value == ScalaDotty) Seq.empty // Just to make IntelliJ happy
if (scalaVersion.value == ScalaDotty) Seq.empty // Just to make IntelliJ happy
else Seq("com.github.pureconfig" %% "pureconfig" % pureconfigVersion)
}

Expand Down Expand Up @@ -144,7 +141,6 @@ lazy val zioConfig = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(buildInfoSettings("zio.config"))
.settings(macroDefinitionSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"org.scala-lang.modules" %% "scala-collection-compat" % "2.8.1",
Expand All @@ -154,7 +150,6 @@ lazy val zioConfig = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)

lazy val zioConfigJS = zioConfig.js
.settings(crossScalaVersions --= Seq("2.11"))
.settings(libraryDependencies += "dev.zio" %%% "zio-test-sbt" % zioVersion % Test)

lazy val zioConfigJVM = zioConfig.jvm
Expand All @@ -170,7 +165,6 @@ lazy val zioConfigAws = crossProject(JVMPlatform)
.settings(crossProjectSettings)
.settings(dottySettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"com.amazonaws" % "aws-java-sdk-ssm" % awsVersion,
"dev.zio" %% "zio-streams" % zioVersion,
Expand All @@ -190,7 +184,6 @@ lazy val zioConfigZioAws = crossProject(JVMPlatform)
.settings(crossProjectSettings)
.settings(dottySettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"dev.zio" %% "zio-aws-ssm" % zioAwsVersion,
"dev.zio" %% "zio-streams" % zioVersion,
Expand All @@ -210,7 +203,6 @@ lazy val zioConfigRefined = crossProject(JVMPlatform)
.settings(crossProjectSettings)
.settings(dottySettings)
.settings(
crossScalaVersions --= Seq("2.11"),
refinedDependencies,
libraryDependencies ++=
Seq(
Expand All @@ -228,7 +220,6 @@ lazy val zioConfigPureconfig = crossProject(JVMPlatform)
.settings(stdSettings("zio-config-pureconfig"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
pureconfigDependencies,
libraryDependencies ++=
Seq(
Expand All @@ -248,7 +239,6 @@ lazy val examples = crossProject(JVMPlatform)
.settings(stdSettings("zio-config-examples"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
publish / skip := true,
fork := true,
magnoliaDependencies,
Expand Down Expand Up @@ -289,11 +279,10 @@ lazy val zioConfigMagnolia = crossProject(JVMPlatform)
.settings(crossProjectSettings)
.settings(dottySettings)
.settings(
crossScalaVersions --= Seq("2.11"),
magnoliaDependencies,
scalacOptions ++= {
if (scalaVersion.value == ScalaDotty) {
Seq.empty
Seq("-Xmax-inlines", "64")
} else {
Seq("-language:experimental.macros")
}
Expand All @@ -314,7 +303,6 @@ lazy val zioConfigTypesafe = crossProject(JVMPlatform)
.settings(crossProjectSettings)
.settings(dottySettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.4.2",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -332,7 +320,6 @@ lazy val zioConfigYaml = crossProject(JVMPlatform)
.settings(stdSettings("zio-config-yaml"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"org.snakeyaml" % "snakeyaml-engine" % "2.6",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -350,7 +337,6 @@ lazy val zioConfigXml = crossProject(JVMPlatform)
.settings(stdSettings("zio-config-xml"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"dev.zio" %% "zio-parser" % "0.1.9",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -368,7 +354,7 @@ lazy val zioConfigScalaz = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(stdSettings("zio-config-scalaz"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11", Scala212),
crossScalaVersions --= Seq(Scala212),
libraryDependencies ++= Seq(
"org.scalaz" %% "scalaz-core" % "7.4.0-M13",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -386,7 +372,6 @@ lazy val zioConfigCats = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(stdSettings("zio-config-cats"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.8.0",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -404,7 +389,6 @@ lazy val zioConfigEnumeratum = crossProject(JSPlatform, JVMPlatform, NativePlatf
.settings(stdSettings("zio-config-enumeratum"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.7.0",
"dev.zio" %% "zio-test" % zioVersion % Test,
Expand All @@ -421,7 +405,6 @@ lazy val zioConfigTypesafeMagnoliaTests = crossProject(JVMPlatform)
.settings(stdSettings("zio-config-typesafe-magnolia-tests"))
.settings(crossProjectSettings)
.settings(
crossScalaVersions --= Seq("2.11"),
publish / skip := true,
libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.4.2",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,14 @@ trait ConfigDocsModule {
)
)

case Config.Switch(c, map) =>
ConfigDocs.DynamicMap(
loop(descriptions, c, latestPath, alreadySeen),
map.map { case (k, v) =>
k.toString -> loop(descriptions, v, latestPath, alreadySeen)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases k will be String, but I wonder if there could be a better support for polymorphic key type of Config.Switch[A, B].

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's going to be hard at DynamicMap level in zio core, as this key gets propagated all over.

}
)

case Config.Described(c, desc) =>
val descri: ConfigDocs.Description =
ConfigDocs.Description(latestPath, desc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ trait ConfigSyntax {
case config: FallbackWith[B] => FallbackWith(loop(config.first), loop(config.second), config.f)
case config: Fallback[B] => Fallback(loop(config.first), loop(config.second))
case Sequence(config) => Sequence(loop(config))
case Switch(config, map) => Switch(config, map.map { case (k, v) => k -> loop(v) })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I wonder if Config#mapKey extension method is still necessary, because now I found it more idiomatic to adjust the keys using ConfigProvider. (e.g. ConfigProvider#kebabCase)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will keep it for now.

case Nested(name, config) => Nested(f(name), loop(config))
case MapOrFail(original, mapOrFail) => MapOrFail(loop(original), mapOrFail)
case Table(valueConfig) => Table(loop(valueConfig))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ final case class describe(describe: String) extends StaticAnnotation
final case class name(name: String) extends StaticAnnotation

/**
* nameWithLabel can be used for class names, such that the name of the class should be part of the product with keyName
* discriminator can be used for class names, such that the name of the class should be part of the product with keyName
* as `keyName`.
*
* Example:
* {{{
* @nameWithLabel("type")
* @discriminator("type")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

* sealed trait FooBar
* case class Bar(x: Int) extends FooBar
* case class Foo(y: String) extends FooBar
Expand Down Expand Up @@ -48,12 +48,12 @@ final case class name(name: String) extends StaticAnnotation
*
* }}}
*
* If annotation is `name` instead of `nameWithLabel`, then name of the case class becomes a parent node
* If annotation is `name` instead of `discriminator`, then name of the case class becomes a parent node
*
* {{{
* Foo : {
* x : Int
* }
* }}}
*/
final case class nameWithLabel(keyName: String = "type") extends StaticAnnotation
final case class discriminator(keyName: String = "type") extends StaticAnnotation
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package zio.config.examples.autoderivation

import zio.config._
import zio.config.derivation.{name, nameWithLabel}
import zio.config.derivation.{name, discriminator}
import zio.config.examples.typesafe.EitherImpureOps
import zio.config.magnolia.deriveConfig
import zio.config.typesafe.TypesafeConfigProvider
Expand All @@ -20,7 +20,7 @@ import examples._
* }
* }}}
*
* Note that all sealed traits should be annotated with @nameWithLabel
* Note that all sealed traits should be annotated with @discriminator
*/
object AutoDerivationSealedTraitPureConfig extends App with EitherImpureOps {

Expand All @@ -31,7 +31,7 @@ object AutoDerivationSealedTraitPureConfig extends App with EitherImpureOps {
final case class AppConfig(awsConfig: AwsConfig, appName: String)
final case class AwsConfig(field: RandomSealedTrait1)

@nameWithLabel("type")
@discriminator("type")
sealed trait RandomSealedTrait1

object RandomSealedTrait1 {
Expand All @@ -48,7 +48,7 @@ object AutoDerivationSealedTraitPureConfig extends App with EitherImpureOps {

}

@nameWithLabel("type")
@discriminator("type")
sealed trait RandomSealedTrait2

object RandomSealedTrait2 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package zio.config.examples.typesafe

import zio.ConfigProvider
import zio.config._
import zio.config.derivation.nameWithLabel
import zio.config.derivation.discriminator
import zio.config.magnolia._

import typesafe._

object PureConfigInterop extends App with EitherImpureOps {

@nameWithLabel()
@discriminator()
sealed trait X

object X {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package zio.config.examples.typesafe

import zio.ConfigProvider
import zio.config.derivation.nameWithLabel
import zio.config.derivation.discriminator
import zio.config._, typesafe._, magnolia._

object SealedTraitListExample extends App {

@nameWithLabel
@discriminator
sealed trait DataTransformation

case class CastColumns(dataTypeMapper: Map[String, String]) extends DataTransformation
Expand Down
Loading