validation

package validation

Visibility
  1. Public
  2. All

Type Members

  1. final class NonEmptyVector[+A] extends Serializable

    A Vector that is guaranteed to be non-empty.

  2. sealed trait Result[+E, +A] extends Product with Serializable

    Represents a value of one of two states:

    Represents a value of one of two states:

    It is similar to Either or a more generic Try.

    Motivation

    Scalas Either is unbiased, meaning it treats its two sides equally and requires one to explicitly state on which side one wants to work on. More often that not, one side is representing the error or invalid part and one side representing the success or valid part.

    Result sets the invalid side on the left and the valid side on the right and assumes, that one wants to primarily work on the right/valid side. This is similar to Try, which fixes the invalid type to Throwable.

    Example:

    import validation._, Result._
    
    case class Person(name: String)
    
    def validateName(input: String): Result[String, String] =
      if (input.trim.isEmpty)
        invalid("name must not be empty")
      else
        valid(input)
    
    List("Bernd", "").map(validateName(_).map(Person.apply))
    
    // List[Result[String,Person]] = List(
    //   Valid(Person(Bernd)),
    //   Invalid(name must not be empty)
    // )

    Both, Either and Try, cannot accumulate errors, but are typically aborting with the first failure, making them disadvantageous for parsing and validating data on system boundaries. For example, parsing a JSON data structure can lead to multiple issues and it is good measure to report as many errors as you can back to the user. With Either or Try, only one error at the time gets reported, leading to the user to submit a fixed version only to encounter, that they have to fixed yet another error.

    Result can accumulate errors and thus allows to report as many of them as possible. There are multiple ways to combine two or more Results, for a detailed description, see their respective documentation.

    Example:

    import validation._, Result._
    
    case class Person(name: String, age: Int)
    
    def validateName(input: String): Result[String, String] =
      if (input.trim.isEmpty)
        invalid("name must not be empty")
      else
        valid(input)
    
    def validateAge(input: String): Result[String, Int] = {
      val ageVal =
        if (input.trim.isEmpty)
          invalid("age must not be empty")
        else
          Result.parseInt(input).invalidMap(_.getMessage)
      ageVal.filter(_ >= 0, "age must be positive")
    }
    
    def parsePerson(inName: String, inAge: String): Result[List[String], Person] = {
      val nameVal = validateName(inName).invalidMap(List(_))
      val ageVal = validateAge(inAge).invalidMap(List(_))
      (nameVal and ageVal) apply Person
    }
    
    val inputs = List(
      ("Bernd", "42"),
      ("Ralle", ""),
      ("Ronny", "foo"),
      ("", "-1337")
    )
    
    inputs.map((parsePerson _).tupled)
    
    // List[Result[List[String],Person]] = List(
    //   Valid(Person(Bernd,42)),
    //   Invalid(List(age must not be empty)),
    //   Invalid(List(For input string: "foo")),
    //   Invalid(List(name must not be empty, age must be positive))
    // )
    E

    the Invalid type

    A

    the Valid type

    Since

    0.1.0

Value Members

  1. object NonEmptyVector extends Serializable

  2. object Result extends Serializable

    Companion object for Result

    Companion object for Result

    provides many factories and creators for Result instances

    Since

    0.1.0

Ungrouped