iniyanp
6/5/2017 - 8:48 PM

Use of Validation

Use of Validation

import scalaz._
import Scalaz._

def convertToInt(s:String):Validation[String, Int] = {
  try{
    Success(s.toInt)
  }catch {
    case ex:NumberFormatException => {
      println(ex)
      Failure(ex.getMessage)
    }
  }
}

val p:Option[Int] = convertToInt("sd1").fold( err => None, value => Some(value))

//For comprehension breaks if there is any failure in the middle.
import scalaz._
import Scalaz._

val p = -\/("Failed")
val p1 = -\/("Failed again")
val q = \/-("Success")
val q1 = \/-("Success again")

//Once it thorws exception in the middle of for-comprehension.
//it never gets executed.
//Right biased

for{
  a <- q
  c <- p
  b <- q1
}yield(a,b) //scalaz.\/[String,(String, String)] = -\/(Failed)

//To change that, use toRightDisjunction.The drawback is we can get only first error.
case class ModifiedPerson(fname:String, lname:String, address:String)

val p7:Person = Person("Iniyan",None)

val res: \/[String,(ModifiedPerson)] = for{
  fname <- Some("Mr." + p7.firstName).toRightDisjunction("FirstName shouldn't be empty")
  lname <- p7.lastName.toRightDisjunction("Provide last name")
  address <- p7.address.toRightDisjunction("Provide Address")
}yield(ModifiedPerson(fname, lname, address))

res //prints scalaz.\/[String,ModifiedPerson] = -\/(Provide last name)

//To get all the errors use, Validation.
import scalaz.ValidationNel
import scalaz._
import Scalaz._

sealed abstract class PersonError extends Product with Serializable

final case class MustHaveLastName(id:String) extends PersonError {
  override def toString: String = s"${id} should have last name"
}
final case class MustHaveAddress(id:String) extends PersonError {
  override def toString: String = s"${id} should have address"
}

case class Person(id:String, firstName:String, lastName:Option[String]=None,address:Option[String]=None)
case class ModifiedPerson(id:String, fname:String, lname:String, address:String)

def checkLastName(id:String,lname:Option[String]):ValidationNel[PersonError,String] = {
  lname match {
    case Some(value) => value.success
    case None => MustHaveLastName(id).failureNel
  }
}

def checkAddress(id:String, address:Option[String]):ValidationNel[PersonError,String] = {
  address match {
    case Some(value) => value.success
    case None => MustHaveAddress(id).failureNel
  }
}


def constructModPerson(p:Person):Validation[NonEmptyList[PersonError], ModifiedPerson] = {

  (checkLastName(p.id, p.lastName) |@| checkAddress(p.id,p.address) ){ (l, a) => new ModifiedPerson(p.id, "Mr." + p.firstName,l, a) }

}

//val p8 = constructModPerson(Person("Iniyan",Some("Paramasivam"),Some("USA")))
val p8 = constructModPerson(Person("1","Iniyan"))
val p9:Option[ModifiedPerson] = p8.fold(f => {
  println("Error is  " +f.list.mkString(","))
  None
}, person => Some(person))

//Result:
//p8: scalaz.Validation[scalaz.NonEmptyList[PersonError],ModifiedPerson] = Failure(NonEmptyList(1 should have last name, 1 should have address))
//Error is  1 should have last name,1 should have address
//p9: Option[ModifiedPerson] = None