ValidationPolicy
Encapsulates Field
validation logic. Also there is ValidationPolicyBuilder
which provides convenient syntax to define Field
validation logic
trait ValidationPolicy[P, F[_], V[_], E] { self =>
def validate(field: Field[P]): Rule[F, V, E]
}
Syntaxβ
import jap.fields._
import jap.fields.DefaultAccumulateVM._
case class Email(value: String) extends AnyVal
object Email {
//Policy is interface with 1 validate method, so you can do so
implicit val policy: Policy[Email] = _.map(_.value).all(_.nonEmpty, _.maxSize(40))
}
case class Request(name: String, email: Email, age: Int, hasParrot: Boolean)
object Request {
implicit val policy: Policy[Request] =
Policy
.builder[Request]
.subRule(_.name)(_.minSize(4), _.maxSize(48)) //runs all validations combining using and
.subRule(_.email)(_.validate) //Reuse Email Policy
.subRule(_.age, _.hasParrot)((age, hasParrot) => age > 48 || (age > 22 && hasParrot.isTrue)) // 2 fields rule
.build
}
Field(Request("", Email(""), 23, true)).validate.effect // This will use implicit policy to validate
// res1: Accumulate[ValidationError] = Invalid(
// errors = List(
// MinSize(path = FieldPath(parts = List(Path(value = "name"))), size = 4),
// NonEmpty(path = FieldPath(parts = List(Path(value = "email"))))
// )
// ) // This will use implicit policy to validate
Field(Request("1234", Email("ann@gmail.com"), 23, true)).validateEither
// res2: Either[List[ValidationError], Request] = Right(
// value = Request(
// name = "1234",
// email = Email(value = "ann@gmail.com"),
// age = 23,
// hasParrot = true
// )
// )