validation
package validation
- Alphabetic
- Public
- All
Type Members
-
final
class
NonEmptyVector
[+A] extends Serializable
A Vector that is guaranteed to be non-empty.
-
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
Eitheror a more genericTry.Motivation
Scalas
Eitheris 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.Resultsets 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 toTry, which fixes the invalid type toThrowable.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,
EitherandTry, 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. WithEitherorTry, 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.Resultcan accumulate errors and thus allows to report as many of them as possible. There are multiple ways to combine two or moreResults, 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
Invalidtype- A
the
Validtype
- Since
0.1.0