Let this be the definition of your Date types:
sealed trait Date {
def year: Int
}
case class Year(year: Int) extends Date
case class YearMonth(year: Int, month: Int) extends Date
case class YearWeek(year: Int, week: Int) extends Date
case class YearMonthDay(year: Int, month: Int, day: Int) extends Date
In your question there are problems when value is not defined, or when it is empty string, or when value is present, but it is not a number. So you can use common function readInt to read optional integer from JSON. In case if value is not present or if value is empty or non-integer, the result of function will be scala.util.Failure.
def parseDate(dateJson: JsValue): Try[Date] = {
def readInt(fieldName: String): Try[Int] =
(dateJson \ fieldName).asOpt[String].filter(_.nonEmpty).map(x => Try(x.toInt))
.getOrElse(Failure(new IllegalArgumentException(s"$fieldName is empty")))
val maybeDay: Try[Int] = readInt("day")
val maybeWeek: Try[Int] = readInt("week")
val maybeMonth: Try[Int] = readInt("month")
val maybeYear: Try[Int] = readInt("year")
maybeYear.map { year: Int =>
maybeMonth match {
case Success(month) => maybeDay match {
case Success(day) => YearMonthDay(year, month, day)
case _ => YearMonth(year, month)
}
case _ => maybeWeek match {
case Success(week) => YearWeek(year, week)
case _ => Year(year)
}
}
}
}
My tests:
val date1 = JsObject(Map("year" -> JsString("2001"), "month" -> JsString("11"), "day" -> JsString("30")))
println(parseDate(date1)) // => Success(YearMonthDay(2001,11,30))
val date2 = JsObject(Map("year" -> JsString("2001"), "month" -> JsString("11")))
println(parseDate(date2)) // => Success(YearMonth(2001,11))
val date3 = JsObject(Map("year" -> JsString("2001"), "week" -> JsString("51")))
println(parseDate(date3)) // => Success(YearWeek(2001,51))
val date4 = JsObject(Map("year" -> JsString("")))
println(parseDate(date4)) // => Failure(java.lang.IllegalArgumentException: year is empty)
Sorry for my English
importstatements necessary for it to compile. \$\endgroup\$scala.util.parsing.json.JSONas well as Circe; you seem to be reinventing-the-wheel: tag accordingly. \$\endgroup\$!= ""could be.nonEmpty\$\endgroup\$