pureconfig module
Import
import refined4s.modules.pureconfig.derivation.types.all.given
import refined4s.modules.pureconfig.derivation.*
Use Drived Instances for Pre-defined Types
To make Newtype, Refined and InlinedRefined have ConfigReader and ConfigWriter type-class instances derived from the actual values, you can simply use
import refined4s.modules.pureconfig.derivation.types.all.given
This works only when the actual type already has ConfigReader and ConfigWriter.
Using refined4s.modules.pureconfig.derivation.types.all.given is required only when ConfigReader and/or ConfigWriter is required for the pre-defined types.
So if you want your Newtype or Refined or InlinedRefined to have ConfigReader and ConfigWriter instances,
you can use pre-defined traits for pureconfig or the deriving method instead.
import refined4s.*
import refined4s.types.all.*
import com.typesafe.config.*
import pureconfig.generic.derivation.default.*
import pureconfig.*
import scala.jdk.CollectionConverters.*
With derivation.types.all,
import refined4s.modules.pureconfig.derivation.types.all.given
final case class NewtypeApiConfig(api: NewtypeApiConfig.Api) derives ConfigReader
object NewtypeApiConfig {
final case class Api(
id: PosLong,
baseUri: Uri,
endpointPath: NonEmptyString,
additionalId: PosLong,
) derives ConfigReader
}
val confString =
raw"""api {
| id = 123
| base-uri = "https://localhost:8080"
| endpoint-path = "/v1/blah/blah"
| additional-id = 999
|}
|""".stripMargin
// confString: String = """api {
// id = 123
// base-uri = "https://localhost:8080"
// endpoint-path = "/v1/blah/blah"
// additional-id = 999
// }
// """
ConfigSource.string(confString).load[NewtypeApiConfig]
// res1: Either[ConfigReaderFailures, NewtypeApiConfig] = Right(
// value = NewtypeApiConfig(
// api = Api(
// id = 123L,
// baseUri = "https://localhost:8080",
// endpointPath = "/v1/blah/blah",
// additionalId = 999L
// )
// )
// )
With Explicit Pre-defined Pureconfig Support
There are the following pre-defined traits to support pureconfig ConfigReader and ConfigWriter.
refined4s.modules.pureconfig.derivation.PureconfigConfigWriterrefined4s.modules.pureconfig.derivation.PureconfigNewtypeConfigReaderrefined4s.modules.pureconfig.derivation.PureconfigRefinedConfigReader
This works only when the actual type already has ConfigReader and ConfigWriter.
import refined4s.*
import refined4s.types.all.*
import refined4s.modules.pureconfig.derivation.*
import refined4s.modules.pureconfig.derivation.types.all.given
import com.typesafe.config.*
import pureconfig.generic.derivation.default.*
import pureconfig.*
import scala.jdk.CollectionConverters.*
final case class NewtypeApiConfig(api: NewtypeApiConfig.Api) derives ConfigReader
object NewtypeApiConfig {
final case class Api(
id: Api.Id,
baseUri: Api.NewtypeBaseUri,
endpointPath: Api.RefinedEndpointPath,
additionalId: Api.InlinedRefinedNewtypeId,
) derives ConfigReader
object Api {
type Id = Id.Type
object Id extends InlinedRefined[Long], PureconfigRefinedConfigReader[Long] {
override inline val inlinedExpectedValue = "a positive Long"
override inline def invalidReason(a: Long): String =
"It must be a positive Long"
override inline def predicate(a: Long): Boolean = a > 0L
override inline def inlinedPredicate(inline a: Long): Boolean = a > 0L
}
type NewtypeBaseUri = NewtypeBaseUri.Type
object NewtypeBaseUri extends Newtype[Uri], PureconfigNewtypeConfigReader[Uri]
type RefinedEndpointPath = RefinedEndpointPath.Type
object RefinedEndpointPath extends Refined[String], PureconfigRefinedConfigReader[String] {
override inline def invalidReason(a: String): String =
"It must be a non-empty String"
override inline def predicate(a: String): Boolean = a != ""
}
type InlinedRefinedNewtypeId = InlinedRefinedNewtypeId.Type
object InlinedRefinedNewtypeId extends Newtype[PosLong], PureconfigNewtypeConfigReader[PosLong]
}
}
val confString =
raw"""api {
| id = 123
| base-uri = "https://localhost:8080"
| endpoint-path = "/v1/blah/blah"
| additional-id = 999
|}
|""".stripMargin
// confString: String = """api {
// id = 123
// base-uri = "https://localhost:8080"
// endpoint-path = "/v1/blah/blah"
// additional-id = 999
// }
// """
ConfigSource.string(confString).load[NewtypeApiConfig]
// res3: Either[ConfigReaderFailures, NewtypeApiConfig] = Right(
// value = NewtypeApiConfig(
// api = Api(
// id = 123L,
// baseUri = "https://localhost:8080",
// endpointPath = "/v1/blah/blah",
// additionalId = 999L
// )
// )
// )
With deriving Method
If you want to have explicit ConfigReader and ConfigWriter type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.
This works only when the actual type already has ConfigReader and ConfigWriter.
import refined4s.*
import refined4s.types.all.*
import refined4s.modules.pureconfig.derivation.*
import refined4s.modules.pureconfig.derivation.types.all.given
import com.typesafe.config.*
import pureconfig.generic.derivation.default.*
import pureconfig.*
import scala.jdk.CollectionConverters.*
final case class NewtypeApiConfig(api: NewtypeApiConfig.Api) derives ConfigReader
object NewtypeApiConfig {
final case class Api(
id: Api.Id,
baseUri: Api.NewtypeBaseUri,
endpointPath: Api.RefinedEndpointPath,
additionalId: Api.InlinedRefinedNewtypeId,
) derives ConfigReader
object Api {
type Id = Id.Type
object Id extends InlinedRefined[Long] {
override inline val inlinedExpectedValue = "a positive Long"
override inline def invalidReason(a: Long): String =
"It must be a positive Long"
override inline def predicate(a: Long): Boolean = a > 0L
override inline def inlinedPredicate(inline a: Long): Boolean = a > 0L
given configReaderId: ConfigReader[Id] = deriving[ConfigReader]
}
type NewtypeBaseUri = NewtypeBaseUri.Type
object NewtypeBaseUri extends Newtype[Uri] {
given configReaderNewtypeBaseUri: ConfigReader[NewtypeBaseUri] = deriving[ConfigReader]
}
type RefinedEndpointPath = RefinedEndpointPath.Type
object RefinedEndpointPath extends Refined[String] {
override inline def invalidReason(a: String): String =
"It must be a non-empty String"
override inline def predicate(a: String): Boolean = a != ""
given configReaderRefinedEndpointPath: ConfigReader[RefinedEndpointPath] = deriving[ConfigReader]
}
type InlinedRefinedNewtypeId = InlinedRefinedNewtypeId.Type
object InlinedRefinedNewtypeId extends Newtype[PosLong] {
given configReaderInlinedRefinedNewtypeId: ConfigReader[InlinedRefinedNewtypeId] = deriving[ConfigReader]
}
}
}
val confString =
raw"""api {
| id = 123
| base-uri = "https://localhost:8080"
| endpoint-path = "/v1/blah/blah"
| additional-id = 999
|}
|""".stripMargin
// confString: String = """api {
// id = 123
// base-uri = "https://localhost:8080"
// endpoint-path = "/v1/blah/blah"
// additional-id = 999
// }
// """
ConfigSource.string(confString).load[NewtypeApiConfig]
// res5: Either[ConfigReaderFailures, NewtypeApiConfig] = Right(
// value = NewtypeApiConfig(
// api = Api(
// id = 123L,
// baseUri = "https://localhost:8080",
// endpointPath = "/v1/blah/blah",
// additionalId = 999L
// )
// )
// )