<>
is an alias to orElse
.
<>
is an alias to orElse
.
Try this
(configSource
), and if it fails, try that
(configSource
)
For example:
Given three configSources, configSource1
, configSource2
and configSource3
, such that
configSource1 and configSource2 will only have id
and configSource3
act as a global fall-back source.
The following config tries to fetch Id
from configSource1, and if fails, it tries configSource2
,
and if both fails it gets from configSource3
. Age
will be fetched only from configSource3
.
val config = (string("Id") from (configSource1 orElse configSource2) zip int("Age")).to[Person] read(config from configSource3)
Transform keys before getting queried from source.
Transform keys before getting queried from source. Note that, this method could be hardly useful.
Most of the time all you need to use is mapKeys
in ConfigDescriptor
i.e, read(descriptor[Config].mapKeys(f) from ConfigSource.fromMap(source))
If you are still curious to understand mapKeys
in ConfigSource
, then read on, or else
avoid a confusion.
case class Hello(a: String, b: String) val config: ConfigDescriptor[Hello] = (string("a") zip string("b")).to[Hello] However your source is different for some reason (i.e, its not `a` and `b`). Example: { "aws_a" : "1" "aws_b" : "2" } If you are not interested in changing the `descriptor` or `case class`, you have a freedom to pre-map keys before its queried from ConfigSource val removeAwsPrefix = (s: String) = s.replace("aws", "") val source = ConfigSource.fromMap(map) val updatedSource = source.mapKeys(removeAwsPrefix) read(config from updatedSource) // This is exactly the same as def addAwsPrefix(s: String) = "aws_" + s read(config.mapKeys(addAwsPrefix) from source)
Memoize the effect required to form the Reader.
Memoize the effect required to form the Reader.
Every ConfigSource at the core is just a Reader
,
which is essentially a function that goes from PropertyTreePath
to an actual PropertyTree
.
i.e, f: PropertyTreePath[String] => IO[ReadError[String], PropertyTree[String, String]
Later on for each key
represented as PropertyTreePath[String]
internally, f
is used to
applied to get the value as a PropertyTree
itself.
Internal details:
This function f
can be retrieved under an ZManaged effect. This implies it may involve an IO with managing resources
to even form this function. Example: In order to retrieve a property-tree corresponding to a key (PropertyTreePath),
it requires a database connection in the very first instance.
// pseudo-logic, doesn't compile
val source: ConfigSource = ConfigSource.Reader( ZManaged(getDatabaseConnection) .flatMap(connection => (key: PropertyTreePath[String] => IO.effect(connection.getStatement.executeQuery(s"get key from table"))) )
Note that ConfigSource
has a generalised memoize
function that allows you to memoize the effect required to form the
function. In the context of the above example, with source.memoize
we acquire only a single connection to retrieve
the values for all the keys in your product/coproduct for an instance of read
.
Try this
(configSource
), and if it fails, try that
(configSource
)
Try this
(configSource
), and if it fails, try that
(configSource
)
For example:
Given three configSources, configSource1
, configSource2
and configSource3
, such that
configSource1 and configSource2 will only have id
and configSource3
act as a global fall-back source.
The following config tries to fetch Id
from configSource1, and if fails, it tries configSource2
,
and if both fails it gets from configSource3
. Age
will be fetched only from configSource3
.
val config = (string("Id") from (configSource1 orElse configSource2) zip int("Age")).to[Person] read(config from configSource3)
With strictlyOnce
, regardless of the number of times read
is invoked, the effect required to form the Reader
in ConfigSource
is evaluated
strictly once.
With strictlyOnce
, regardless of the number of times read
is invoked, the effect required to form the Reader
in ConfigSource
is evaluated
strictly once. Use strictlyOnce
only if it's really required.
In a normal scenarios, everytime read
is invoked (as in read(desc from source)
), it
should read from the real source.
val sourceZIO = ConfigSource.fromPropertiesFile(...).strictlyOnce for { src <- sourceZIO result1 <- read(config from src) result2 <- read(config from src) } yield (result1, result2)
In this case, the propertiesFile is read only once.
vs
val source: ConfigSource = ConfigSource.fromPropertiesFile(...).memoize for { result1 <- read(config from source) result2 <- read(config from source) } yield (result1, result2)
In this case, the propertiesFile is read once per each read, i.e, twice.
A Layer is assumed to be "memoized" by default, i.e the effect required to form the reader (refer ConfigSource docs) is executed strictly once regardless of number of keys involved, or the number the reads invoked.
A Layer is assumed to be "memoized" by default, i.e the effect required to form the reader (refer ConfigSource docs) is executed strictly once regardless of number of keys involved, or the number the reads invoked.