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:
jap.fields.data.Accumulate
- accumulates errors.jap.fields.data.FailFast
- holds first error that occured. Built usingEither
cats.data.ValidatedNel[_, Unit]
- accumulates. Part of cats modulecats.data.ValidatedNec[_, Unit]
- accumulates. Part of cats moduleList
- accumulates errors. If list is empty means result is valid else contains errors.Either[_, Unit]
- fail fast error.Right[Unit]
is valid,Left[E]
is invalid holding error.Option
- fail fast error.None
is valid,Some[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
Accumulateβ
Validated data type that accumulates errors.
sealed trait Accumulate[+E]
object Accumulate {
case object Valid extends Accumulate[Nothing]
case class Invalid[+E](errors: List[E]) extends Accumulate[E]
}
FailFastβ
Validated data type that returns first error occured. Declared as Option[E]
tagged type.
None
is validSome[E]
holds the error
Syntaxβ
Having Validated for your V[_]
in scope you can use such syntax
Createβ
import jap.fields._
import jap.fields.data.Accumulate
import jap.fields.typeclass.Validated
import jap.fields.syntax.ValidatedSyntax._
val V: Validated[Accumulate] = Accumulate
// V: Validated[[E >: Nothing <: Any] => Accumulate[E]] = jap.fields.data.Accumulate$@2fab6544
val vr1 = V.valid
// vr1: Accumulate[Nothing] = Valid
val vr2 = V.invalid("ERR01")
// vr2: Accumulate[String] = Invalid(errors = List("ERR01"))
val vr3 = "ERR02".invalid[Accumulate]
// vr3: Accumulate[String] = Invalid(errors = List("ERR02"))
val vr4 = V.traverse(List("ERR01", "ERR02"))(V.invalid)
// vr4: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
V.sequence(List(vr1, vr2, vr3))
// res0: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
Operationsβ
vr1.isValid
// res1: Boolean = true
vr2.when(false)
// res2: Accumulate[String] = Valid
vr2.unless(true)
// res3: Accumulate[String] = Valid
vr2.asError("ERROR02")
// res4: Accumulate[String] = Invalid(errors = List("ERROR02"))
vr2.asInvalid(vr4)
// res5: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
vr2.isInvalid
// res6: Boolean = true
vr2.errors
// res7: List[String] = List("ERR01")
vr1 && vr2
// res8: Accumulate[String] = Invalid(errors = List("ERR01"))
vr2.and(vr3)
// res9: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
vr1 || vr2
// res10: Accumulate[String] = Valid
vr2.or(vr3)
// res11: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
List(vr1, vr2, vr3).sequence
// res12: Accumulate[String] = Invalid(errors = List("ERR01", "ERR02"))
List(vr1, vr1).sequence
// res13: Accumulate[Nothing] = Valid
Fail Multiple Fieldsβ
V.traverse is very useful when you want to fail multiple Field`s with same error
import jap.fields.DefaultAccumulateVM._
V.traverse(Field(FieldPath("1"), 1), Field(FieldPath("2"), 2))(_.failMessage("ERROR"))