Skip to content

Commit

Permalink
ConfGet: add getNested method
Browse files Browse the repository at this point in the history
  • Loading branch information
kitbellew committed Aug 12, 2022
1 parent eb67452 commit 9445525
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
3 changes: 3 additions & 0 deletions metaconfig-core/shared/src/main/scala/metaconfig/Conf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ sealed abstract class Conf extends Product with Serializable {
default: T
)(implicit ev: ConfDecoder[T]): Configured[T] =
ConfGet.getOrElse(this, default, path, extraNames: _*)

def getNested[T](keys: String*)(implicit ev: ConfDecoder[T]): Configured[T] =
ConfGet.getNested(this, keys: _*)
}

object Conf {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ object ConfGet {
}
}

@tailrec
def getNested[T](conf: Conf, keys: String*)(
implicit ev: ConfDecoder[T]
): Configured[T] =
keys.headOption match {
case None => ev.read(conf)
case Some(key) =>
conf match {
case obj: Conf.Obj =>
obj.values.collectFirst { case (`key`, v) => v } match {
case Some(v) => getNested(v, keys.tail: _*)
case _ => ConfError.missingField(obj, key).notOk
}
case _ =>
ConfError.typeMismatch(s"Conf.Obj with key '$key'", conf).notOk
}
}

// Copy-pasted from scala.meta inputs because it's private.
// TODO(olafur) expose utility in inputs to get offset from line
private[metaconfig] def getOffsetByLine(chars: Array[Char]): Array[Int] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package metaconfig

class ConfGetSuite extends munit.FunSuite {
import Conf._

test("getNested good") {
val confA = Str("a")
assertEquals(confA.getNested[String](), Configured.Ok("a"))

val confB = Obj("b" -> confA)
assertEquals(confB.getNested[String]("b"), Configured.Ok("a"))

val confC = Obj("c" -> confB)
assertEquals(confC.getNested[String]("c", "b"), Configured.Ok("a"))

val confD = Obj("d" -> confC)
assertEquals(confD.getNested[String]("d", "c", "b"), Configured.Ok("a"))
}

test("getNested fail") {
val confA = Str("a")
assertEquals(
confA.getNested[Boolean]().toEither.left.get.msg,
"""|Type mismatch;
| found : String (value: "a")
| expected : Bool""".stripMargin
)

assertEquals(
confA.getNested[Boolean]("c").toEither.left.get.msg,
"""|Type mismatch;
| found : String (value: "a")
| expected : Conf.Obj with key 'c'""".stripMargin
)

val confB = Obj("b" -> confA)
assertEquals(
confB.getNested[String]("c").toEither.left.get.msg,
"""{"b": "a"} has no field 'c'."""
)
}

}

0 comments on commit 9445525

Please sign in to comment.