Validated
Defines Validated capabilities for V[_], so that Fields know how to use it when validating.
Also this typeclass has strategy field that will give a hint for short-circuiting while validating.
Instancesβ
Predefined instances:
Listalised asjap.fields.Accumulate- accumulates errors.Nilis valid,List[E]is invalid holding errorsOptionaliased asjap.fields.FailFast- holds first error that occured.Noneis valid,Some[E]is invalid holding errorcats.data.ValidatedNel[_, Unit]- accumulates. Part of cats modulecats.data.ValidatedNec[_, Unit]- accumulates. Part of cats moduleEither[_, Unit]- fail fast error.Right[Unit]is valid,Left[E]is invalid holding error.
If you need you can use your own Validated data type by creating typeclass instance for it.
Extend AccumulateLike if your type should accumulate errors or if it should fail with first error occured use FailFastLike
You will need to implement a hew methods, here is example for List
import fields.typeclass.AccumulateLike
implicit object ListValidated extends AccumulateLike[List] {
def valid[E]: List[E] = Nil
def invalid[E](e: E): List[E] = List(e)
def and[E](va: List[E], vb: List[E]): List[E] = va ::: vb
def isValid[E](v: List[E]): Boolean = v.isEmpty
def map[E](v: List[E])(f: E => E): List[E] = v.map(f)
}
Syntaxβ
Having Validated for your V[_] in scope you can use such syntax
Createβ
import fields._
import fields.typeclass.Validated
import fields.syntax.ValidatedSyntax._
val V = Validated.Accumulate
// V: ListValidated = fields.typeclass.Validated$ListValidated$@179d5ba1
val vr1 = V.valid
// vr1: List[Nothing] = List()
val vr2 = V.invalid("ERR01")
// vr2: List[String] = List("ERR01")
val vr3 = "ERR02".invalid[Accumulate]
// vr3: List[String] = List("ERR02")
val vr4 = V.traverse(List("ERR01", "ERR02"))(V.invalid)
// vr4: List[String] = List("ERR01", "ERR02")
V.sequence(List(vr1, vr2, vr3))
// res0: List[String] = List("ERR01", "ERR02")
Operationsβ
vr1.isValid
// res1: Boolean = true
vr2.when(false)
// res2: List[String] = List()
vr2.unless(true)
// res3: List[String] = List()
vr2.asError("ERROR02")
// res4: List[String] = List("ERROR02")
vr2.asInvalid(vr4)
// res5: List[String] = List("ERR01", "ERR02")
vr2.isInvalid
// res6: Boolean = true
vr2.errors
// res7: List[String] = List("ERR01")
vr1 && vr2
// res8: List[String] = List("ERR01")
vr2.and(vr3)
// res9: List[String] = List("ERR01", "ERR02")
vr1 || vr2
// res10: List[String] = List()
vr2.or(vr3)
// res11: List[String] = List("ERR01", "ERR02")
List(vr1, vr2, vr3).sequence
// res12: List[String] = List("ERR01", "ERR02")
List(vr1, vr1).sequence
// res13: List[Nothing] = List()
Fail Multiple Fieldsβ
V.traverse is very useful when you want to fail multiple Field`s with same error
import fields.value.FieldsDsl.default._
V.traverse(Field(FieldPath("1"), 1), Field(FieldPath("2"), 2))(_.failMessage("ERROR"))
HasErrorsβ
Helper typeclass that allows to extract errors from your V[_] type.
trait HasErrors[V[_]] {
def errors[E](v: V[E]): List[E]
}
HasFieldPathβ
Helper typeclass that allows to extract field path from your E error type.
trait HasFieldPath[E] {
def getPath(e: E): FieldPath
}
PrependPathβ
Helper typeclass that allows to prepend field path to your E error type. Mainly used for lens module
trait PrependPath[E] {
def prependPath(path: FieldPath, e: E): E
}
MapKeyToPartβ
Helper typeclass that allows to map key with index to FieldPart of your E error type. Used for MapSyntax for both value and lens modules
trait MapKeyToPart[K] {
def toPart(key: K, index: Int): FieldPart
}