- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Accumulating Validation Errors
Sun, 2011-10-30, 12:03
Hi
I'm trying to use Validation but I want to accumulate all the error strings in my output. The horribly messy code below is the result. First I accumulate my validations, then I check to see if any of them are actual failures and collect the strings together. If any failures I return a fail - but I have to cast it with asInstanceOf. If I succeed, the easiest way of extract the success side is with a for.
It works, but is there a nicer way to do it? I don't (yet) get the totality of the scalaz library and really don't have time today to learn it all. I've got to get something working quickly.
Code is below (addKeyword simply puts the record name onto any error messages that occur for ease of finding the problem).
def buildLoadRateTerm(node: Node): Validation[NonEmptyList[String], (LoadRateTerm, String)] = { val name = getName(node) val keyword = name match { case Success(name) => "Loadrate " + name + ": " case _ => "Loadrate with no name: " } val loadCategoryName = addKeyword(keyword, getString(node, "loadCategory")) val crewFactor = addKeyword(keyword, getValue[Double](node, "crewFactor")) val timePerUnit = addKeyword(keyword, getValue[Duration](node, "timePerUnit")) val timePerWeight = addKeyword(keyword, getValue[Duration](node, "timePerWeight")) val timePerVolume = addKeyword(keyword, getValue[Duration](node, "timePerVolume"))
val allMessages = List(name, loadCategoryName, crewFactor, timePerUnit, timePerWeight, timePerVolume) filter (_.isFailure) map (_ match { case Failure(msgs) => msgs.list }) flatten if (allMessages.size > 0) (allMessages.fail).asInstanceOf[Validation[NonEmptyList[String], (LoadRateTerm, String)]] else for { a <- name b <- loadCategoryName c <- crewFactor d <- timePerUnit e <- timePerWeight f <- timePerVolume } yield (LoadRateTerm(a, c, d, e, f), b) }
CheersTim
I'm trying to use Validation but I want to accumulate all the error strings in my output. The horribly messy code below is the result. First I accumulate my validations, then I check to see if any of them are actual failures and collect the strings together. If any failures I return a fail - but I have to cast it with asInstanceOf. If I succeed, the easiest way of extract the success side is with a for.
It works, but is there a nicer way to do it? I don't (yet) get the totality of the scalaz library and really don't have time today to learn it all. I've got to get something working quickly.
Code is below (addKeyword simply puts the record name onto any error messages that occur for ease of finding the problem).
def buildLoadRateTerm(node: Node): Validation[NonEmptyList[String], (LoadRateTerm, String)] = { val name = getName(node) val keyword = name match { case Success(name) => "Loadrate " + name + ": " case _ => "Loadrate with no name: " } val loadCategoryName = addKeyword(keyword, getString(node, "loadCategory")) val crewFactor = addKeyword(keyword, getValue[Double](node, "crewFactor")) val timePerUnit = addKeyword(keyword, getValue[Duration](node, "timePerUnit")) val timePerWeight = addKeyword(keyword, getValue[Duration](node, "timePerWeight")) val timePerVolume = addKeyword(keyword, getValue[Duration](node, "timePerVolume"))
val allMessages = List(name, loadCategoryName, crewFactor, timePerUnit, timePerWeight, timePerVolume) filter (_.isFailure) map (_ match { case Failure(msgs) => msgs.list }) flatten if (allMessages.size > 0) (allMessages.fail).asInstanceOf[Validation[NonEmptyList[String], (LoadRateTerm, String)]] else for { a <- name b <- loadCategoryName c <- crewFactor d <- timePerUnit e <- timePerWeight f <- timePerVolume } yield (LoadRateTerm(a, c, d, e, f), b) }
CheersTim
The short answer is that you need liftFailNEL which lifts string validation errors into NonEmptyList[String]
You're also better off using an applicative functor for constructing LoadRateTerm.
eg see the lines from ExampleValidation.scala in the examples project of the scalaz distribution: case class Person(name: Name, age: Age) def mkPerson(name: String, age: Int) = (Name(name).liftFailNel ⊛ Age(age).liftFailNel){ (n, a) => Person(n, a)}
If the baby stays silent for much longer I'll post up something more detailed.
-Rob
On Sun, Oct 30, 2011 at 11:03 AM, Tim P <tim.pigden@optrak.com> wrote: