Last active
April 4, 2023 21:44
-
-
Save Ghurtchu/904049da40a3fb892c73490e4d83f64c to your computer and use it in GitHub Desktop.
Accumulative Validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object ValidatorImpl { | |
sealed trait Validated[+E, +S] | |
object Validated { | |
final case class Passed[S](value: S) extends Validated[Nothing, S] | |
final case class Failed[E](errors: List[E]) extends Validated[E, Nothing] | |
} | |
trait Validator[+E, S] { previous => | |
import Validator.PredicateMeta | |
protected def input: S | |
protected def failedPredicates[E1 >: E]: List[PredicateMeta[E1, S]] = List.empty | |
def satisfying[E1 >: E](f: S => Boolean, failureReason: E1): Validator[E1, S] = new Validator[E1, S] { | |
override def input: S = previous.input | |
override def failedPredicates[E2 >: E1]: List[PredicateMeta[E2, S]] = | |
if (f(input)) previous.failedPredicates | |
else PredicateMeta[E2, S](f, failureReason) :: previous.failedPredicates | |
} | |
def validated: Validated[E, S] = failedPredicates match { | |
case Nil => Validated.Passed(input) | |
case _ => Validated.Failed(failedPredicates.map[E](_.failureReason).reverse) | |
} | |
} | |
object Validator { | |
def apply[E, S](s: S): Validator[E, S] = new Validator[E, S] { | |
override def input: S = s | |
} | |
protected[Validator] final case class PredicateMeta[+E, S](f: S => Boolean, failureReason: E) | |
} | |
def main(args: Array[String]): Unit = { | |
final case class Person(name: String, age: Int) | |
sealed trait PersonValidationError { def reason: String } | |
object PersonValidationError { | |
case object EmptyName extends PersonValidationError { override def reason: String = "Person has an empty name" } | |
case object NonAdult extends PersonValidationError { override def reason: String = "Person is non adult" } | |
} | |
val person = Person("", 14) | |
val validatedPerson = | |
Validator(person) | |
.satisfying(_.name.nonEmpty, PersonValidationError.EmptyName) | |
.satisfying(_.age >= 18, PersonValidationError.NonAdult) | |
.validated | |
validatedPerson match { | |
case Validated.Passed(value) => println(s"passed $value") | |
case Validated.Failed(errors) => println(s"failed: $errors") // List(EmptyName, NonAdult) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment