Syntax
Here is complete list of predefined validation syntax.
Genericβ
import jap.fields._
import jap.fields.DefaultAccumulateVM._
import jap.fields.FieldPathConversions._
val field: Field[Int] = Field("1", 1)
// field: Field[Int] = Field(path = FieldPath(parts = List(Path(value = "1"))), value = 1)
field.ensure(_ == 3, _.failInvalid)
// res0: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Invalid(path = FieldPath(parts = List(Path(value = "1")))))
// )
field.assert(_ == 3, _.invalidError)
// res1: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Invalid(path = FieldPath(parts = List(Path(value = "1")))))
// )
field.check(f => if(false) f.failMessage("A") else f.failMessage("B"))
// res2: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Message(path = FieldPath(parts = List(Path(value = "1"))), error = "B", message = None)
// )
// )
field equalTo 2
// res3: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Equal(path = FieldPath(parts = List(Path(value = "1"))), compared = "2"))
// )
field notEqualTo 1
// res4: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NotEqual(path = FieldPath(parts = List(Path(value = "1"))), compared = "1"))
// )
field equalTo Field("2", 2)
// res5: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Equal(path = FieldPath(parts = List(Path(value = "1"))), compared = ".2"))
// )
field notEqualTo Field("1", 1)
// res6: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NotEqual(path = FieldPath(parts = List(Path(value = "1"))), compared = ".1"))
// )
field in List(2, 3)
// res7: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(OneOf(path = FieldPath(parts = List(Path(value = "1"))), variants = List("2", "3")))
// )
field.all(_ === 2, _ !== 1)
// res8: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Equal(path = FieldPath(parts = List(Path(value = "1"))), compared = "2"),
// NotEqual(path = FieldPath(parts = List(Path(value = "1"))), compared = "1")
// )
// )
field.any(_ === 2, _ !== 3)
// res9: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Valid
field.when(false)(_ !== field.value)
// res10: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Valid
field.unless(true)(_ !== field.value)
// res11: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Valid
implicit val policy: Policy[Int] = _ < 0
// policy: ValidationPolicy[Int, Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = <function1>
field.validate
// res12: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Less(path = FieldPath(parts = List(Path(value = "1"))), compared = "0"))
// )
sealed trait ABC
case class A(a: Int) extends ABC
case class B() extends ABC
case class C() extends ABC
Field[ABC](A(-1)).whenType[A](_.check(_.failMessage("A")))
// res13: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Message(path = FieldPath(parts = List()), error = "A", message = None))
// )
Field[ABC](A(-1)).whenType[A](_.sub(_.a) > 0)
// res14: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Greater(path = FieldPath(parts = List(Path(value = "a"))), compared = "0"))
// )
Field[ABC](A(-1)).whenType[B](_.check(_.failMessage("B")))
// res15: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Valid
Field[ABC](A(-1)).whenType[C](_.check(_.failMessage("B")))
// res16: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Valid
Booleanβ
Field("false", false).isTrue
// res17: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Equal(path = FieldPath(parts = List(Path(value = "false"))), compared = "true"))
// )
Field("true", true).isFalse
// res18: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Equal(path = FieldPath(parts = List(Path(value = "true"))), compared = "false"))
// )
Orderingβ
import java.time.LocalDateTime
val now = LocalDateTime.now
// now: LocalDateTime = 2022-08-09T21:25:08.553
val nowF = Field.from(now)
// nowF: Field[LocalDateTime] = Field(
// path = FieldPath(parts = List(Path(value = "now"))),
// value = 2022-08-09T21:25:08.553
// )
val tomorrow = now.plusDays(1)
// tomorrow: LocalDateTime = 2022-08-10T21:25:08.553
val yesterday = now.minusDays(1)
// yesterday: LocalDateTime = 2022-08-08T21:25:08.553
nowF.isBetween(tomorrow, yesterday)
// res19: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// GreaterEqual(
// path = FieldPath(parts = List(Path(value = "now"))),
// compared = "2022-08-10T21:25:08.553"
// ),
// LessEqual(
// path = FieldPath(parts = List(Path(value = "now"))),
// compared = "2022-08-08T21:25:08.553"
// )
// )
// )
nowF < yesterday
// res20: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Less(path = FieldPath(parts = List(Path(value = "now"))), compared = "2022-08-08T21:25:08.553")
// )
// )
nowF <= yesterday
// res21: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// LessEqual(
// path = FieldPath(parts = List(Path(value = "now"))),
// compared = "2022-08-08T21:25:08.553"
// )
// )
// )
nowF >= tomorrow
// res22: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// GreaterEqual(
// path = FieldPath(parts = List(Path(value = "now"))),
// compared = "2022-08-10T21:25:08.553"
// )
// )
// )
nowF > tomorrow
// res23: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Greater(
// path = FieldPath(parts = List(Path(value = "now"))),
// compared = "2022-08-10T21:25:08.553"
// )
// )
// )
Optionβ
Field(None).isDefined
// res24: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Empty(path = FieldPath(parts = List())))
// )
val someF: Field[Option[Int]] = Field("a", Some(5))
// someF: Field[Option[Int]] = Field(
// path = FieldPath(parts = List(Path(value = "a"))),
// value = Some(value = 5)
// )
someF.isEmpty
// res25: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NonEmpty(path = FieldPath(parts = List(Path(value = "a")))))
// )
someF.some(_ > 10)
// res26: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Greater(path = FieldPath(parts = List(Path(value = "a"))), compared = "10"))
// )
someOrValid {
for {
option <- someF.option
other <- Field("b", Some(2)).option
} yield option < other
}
// res27: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Less(path = FieldPath(parts = List(Path(value = "a"))), compared = ".b"))
// )
Stringβ
val stringF: Field[String] = Field("Ann")
// stringF: Field[String] = Field(path = FieldPath(parts = List()), value = "Ann")
stringF.startsWith("sca")
// res28: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List()),
// error = "string/starts_with",
// message = Some(value = "must start with sca")
// )
// )
// )
stringF.endsWith("la")
// res29: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List()),
// error = "string/ends_with",
// message = Some(value = "must end with la")
// )
// )
// )
Field("").nonEmpty
// res30: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NonEmpty(path = FieldPath(parts = List())))
// )
Field("").nonBlank
// res31: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NonEmpty(path = FieldPath(parts = List())))
// )
stringF.minSize(5)
// res32: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MinSize(path = FieldPath(parts = List()), size = 5))
// )
stringF.maxSize(1)
// res33: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MaxSize(path = FieldPath(parts = List()), size = 1))
// )
stringF.blank
// res34: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Empty(path = FieldPath(parts = List())))
// )
stringF.matchesRegex("scala".r)
// res35: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List()),
// error = "string/match",
// message = Some(value = "must match scala")
// )
// )
// )
stringF.matches("scala")
// res36: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List()),
// error = "string/match",
// message = Some(value = "must match scala")
// )
// )
// )
Iterableβ
val listF: Field[List[Int]] = Field(List(1, 12))
// listF: Field[List[Int]] = Field(path = FieldPath(parts = List()), value = List(1, 12))
listF.each(_ > 10)
// res37: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(Greater(path = FieldPath(parts = List(Index(value = 0))), compared = "10"))
// )
listF.any(_ === 10)
// res38: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Equal(path = FieldPath(parts = List(Index(value = 1))), compared = "10"),
// Equal(path = FieldPath(parts = List(Index(value = 0))), compared = "10")
// )
// )
Field(List()).nonEmpty
// res39: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NonEmpty(path = FieldPath(parts = List())))
// )
listF.minSize(3)
// res40: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MinSize(path = FieldPath(parts = List()), size = 3))
// )
listF.maxSize(1)
// res41: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MaxSize(path = FieldPath(parts = List()), size = 1))
// )
Mapβ
val mapF: Field[Map[String, Int]] = Field(Map("" -> 2, "2" -> 2))
// mapF: Field[Map[String, Int]] = Field(
// path = FieldPath(parts = List()),
// value = Map("" -> 2, "2" -> 2)
// )
mapF.minSize(4)
// res42: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MinSize(path = FieldPath(parts = List()), size = 4))
// )
mapF.maxSize(1)
// res43: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(MaxSize(path = FieldPath(parts = List()), size = 1))
// )
mapF.each(_.second > 4)
// res44: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Greater(path = FieldPath(parts = List(Path(value = ""))), compared = "4"),
// Greater(path = FieldPath(parts = List(Path(value = "2"))), compared = "4")
// )
// )
mapF.eachKey(_.nonEmpty)
// res45: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(NonEmpty(path = FieldPath(parts = List(Path(value = "")))))
// )
mapF.eachValue(_ > 4)
// res46: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Greater(path = FieldPath(parts = List(Path(value = ""))), compared = "4"),
// Greater(path = FieldPath(parts = List(Path(value = "2"))), compared = "4")
// )
// )
mapF.any(_.second > 4)
// res47: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Greater(path = FieldPath(parts = List(Path(value = "2"))), compared = "4"),
// Greater(path = FieldPath(parts = List(Path(value = ""))), compared = "4")
// )
// )
mapF.anyKey(_ === "4")
// res48: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Equal(path = FieldPath(parts = List(Path(value = "2"))), compared = "4"),
// Equal(path = FieldPath(parts = List(Path(value = ""))), compared = "4")
// )
// )
mapF.anyValue(_ > 4)
// res49: Rule[Sync, [E >: Nothing <: Any] => Accumulate[E], ValidationError] = Invalid(
// errors = List(
// Greater(path = FieldPath(parts = List(Path(value = "2"))), compared = "4"),
// Greater(path = FieldPath(parts = List(Path(value = ""))), compared = "4")
// )
// )
Effectfulβ
import jap.fields._
import jap.fields.ZIOInterop._
import jap.fields.fail._
import jap.fields.error._
import zio._
object Validation extends AccumulateVM[Task, ValidationError] with CanFailWithValidationError
import Validation._
def unsafeRun[A](task: Task[A]) = Runtime.global.unsafeRun(task)
def isPositiveApi(number: Int): zio.Task[Boolean] = zio.UIO(number > 0)
val field = Field(FieldPath.fromPath("size"), -1)
// field: Field[Int] = Field(path = FieldPath(parts = List(Path(value = "size"))), value = -1)
unsafeRun(field.ensureF(isPositiveApi, _.failMessage("API: NOT POSITIVE")).effect)
// res51: Accumulate[ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List(Path(value = "size"))),
// error = "API: NOT POSITIVE",
// message = None
// )
// )
// )
unsafeRun(field.assertF(isPositiveApi, _.messageError("API: NOT POSITIVE")).effect)
// res52: Accumulate[ValidationError] = Invalid(
// errors = List(
// Message(
// path = FieldPath(parts = List(Path(value = "size"))),
// error = "API: NOT POSITIVE",
// message = None
// )
// )
// )