All Downloads are FREE. Search and download functionalities are using the official Maven repository.

validation.ValidationResult.scala Maven / Gradle / Ivy

There is a newer version: 0.1.2
Show newest version
package jap
package validation

trait ValidationResult[VR[_]] {
  def getErrors[E](vr: VR[E]): List[E]
  def valid[E]: VR[E]
  def invalid[E](e: => E): VR[E]
  def isValid[E](e: VR[E]): Boolean
  def isInvalid[E](e: VR[E]): Boolean
  def and[E](e1: => VR[E], e2: => VR[E]): VR[E]

  def assert[E](cond: Boolean, error: VR[E]): VR[E] = if (cond) valid[E] else error
  def or[E](e1: => VR[E], e2: => VR[E]): VR[E]      =
    if (this.isValid(e1)) valid
    else if (this.isValid(e2)) valid
    else this.and(e1, e2)

  def sequence[E](results: Iterable[VR[E]]): VR[E] = results.foldLeft(valid[E])(and[E](_, _))
  def sequence[E](results: VR[E]*): VR[E]          = sequence[E](results)

  def invalidPar[E](he: E, te: E*): VR[E] = if (te.isEmpty) invalid(he) else invalidPar(he +: te)
  def invalidPar[E](errors: Iterable[E])  = sequence(errors.map(invalid[E](_)))
}

object ValidationResult {
  def apply[VR[_]](implicit vr: ValidationResult[VR]): ValidationResult[VR] = vr
  implicit class IterableErrorIdOps[E](iterable: Iterable[E]) {
    def invalid[VR[_]: ValidationResult]: VR[E] = ValidationResult[VR].invalidPar(iterable)
  }

  implicit class ErrorIdOps[E](error: E) {
    def invalid[VR[_]: ValidationResult]: VR[E] = ValidationResult[VR].invalid(error)
  }

  implicit class IterableValidationResultOps[VR[_]: ValidationResult, E](iterable: Iterable[VR[E]]) {
    def sequence: VR[E] = ValidationResult[VR].sequence(iterable)
  }

  implicit class ValidationResultOps[VR[_]: ValidationResult, E](vr: => VR[E]) {
    def and(that: => VR[E]): VR[E] = ValidationResult[VR].and(vr, that)
    def or(that: => VR[E]): VR[E]  = ValidationResult[VR].or(vr, that)
    def getErrors: List[E]         = ValidationResult[VR].getErrors(vr)
  }

  sealed abstract class Accumulate[+E]
  implicit object Accumulate extends ValidationResult[Accumulate] {
    case object Valid                                                   extends Accumulate[Nothing]
    case class Invalid[+E] private[validation] (errorsF: () => List[E]) extends Accumulate[E] {
      lazy val errors: List[E] = errorsF()
    }

    def valid[E]: Accumulate[E]            = Accumulate.Valid
    def invalid[E](e: => E): Accumulate[E] = Accumulate.Invalid(() => List(e))

    def isValid[E](a: Accumulate[E]): Boolean   = a == Accumulate.Valid
    def isInvalid[E](a: Accumulate[E]): Boolean = a != Accumulate.Valid

    def and[E](a: => Accumulate[E], b: => Accumulate[E]): Accumulate[E] =
      (a, b) match {
        case (Accumulate.Valid, Accumulate.Valid)                   => Accumulate.Valid
        case (aa: Accumulate.Invalid[E], bb: Accumulate.Invalid[E]) => Accumulate.Invalid(() => aa.errors ++ bb.errors)
        case (_: Accumulate.Invalid[E], _)                          => a
        case _                                                      => b
      }

    def getErrors[E](vr: Accumulate[E]): List[E] = vr match {
      case e: Accumulate.Invalid[E] => e.errors
      case Accumulate.Valid         => Nil
    }
  }

  case class FailFast[+E] private (run: () => Either[E, Unit]) {
    lazy val either = run()
  }
  implicit object FailFast extends ValidationResult[FailFast] {
    def valid[E]: FailFast[E]            = FailFast(() => Right(()))
    def invalid[E](e: => E): FailFast[E] = FailFast(() => Left(e))

    def isValid[E](e: FailFast[E]): Boolean   = e.either.isRight
    def isInvalid[E](e: FailFast[E]): Boolean = e.either.isLeft

    def and[E](e1: => FailFast[E], e2: => FailFast[E]): FailFast[E] = FailFast(() => e1.either.flatMap(_ => e2.either))
    def getErrors[E](vr: FailFast[E]): List[E]                      = vr.either.left.toSeq.toList
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy