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

zio.schema.validation.Predicate.scala Maven / Gradle / Ivy

package zio.schema.validation

import zio.Chunk

sealed trait Predicate[A] { self =>
  type Errors = Chunk[ValidationError]
  type Result = Either[Errors, Errors]
  def validate(value: A): Result
  def contramap[B](f: B => A): Predicate[B] = Predicate.Contramap(Bool.Leaf(self), f)
}

object Predicate {
  sealed trait Str[A] extends Predicate[A]

  object Str {
    final case class MinLength(n: Int) extends Str[String] {

      def validate(value: String): Result =
        if (value.length() >= n)
          Right(Chunk(ValidationError.MaxLength(n, value.length(), value)))
        else
          Left(Chunk(ValidationError.MinLength(n, value.length(), value)))
    }
    final case class MaxLength(n: Int) extends Str[String] {

      def validate(value: String): Result =
        if (value.length() <= n) Right(Chunk(ValidationError.MinLength(n, value.length(), value)))
        else Left(Chunk(ValidationError.MaxLength(n, value.length(), value)))
    }
    final case class Matches(r: Regex) extends Str[String] {

      def validate(value: String): Result =
        if (r.test(value)) Right(Chunk(ValidationError.NotRegexMatch(value, r)))
        else Left(Chunk(ValidationError.RegexMatch(value, r)))
    }
  }

  // A => Boolean
  sealed trait Num[A] extends Predicate[A] {
    def numType: NumType[A]
  }

  object Num {
    final case class GreaterThan[A](numType: NumType[A], value: A) extends Num[A] {

      def validate(v: A): Result =
        if (numType.numeric.compare(v, value) > 0)
          Right(Chunk(ValidationError.LessThan(v, value)))
        else
          Left(Chunk(ValidationError.GreaterThan(v, value)))
    }
    final case class LessThan[A](numType: NumType[A], value: A) extends Num[A] {

      def validate(v: A): Result =
        if (numType.numeric.compare(v, value) < 0)
          Right(Chunk(ValidationError.GreaterThan(v, value)))
        else
          Left(Chunk(ValidationError.LessThan(v, value)))
    }
    final case class EqualTo[A](numType: NumType[A], value: A) extends Num[A] {

      def validate(v: A): Result =
        if (numType.numeric.compare(v, value) == 0)
          Right(Chunk(ValidationError.NotEqualTo(v, value)))
        else
          Left(Chunk(ValidationError.EqualTo(v, value)))
    }
  }

  final case class True[A]() extends Predicate[A] { // A => True
    def validate(value: A): Result = Right(Chunk.empty)
  }

  final case class Optional[A](pred: Bool[Predicate[A]], validNone: Boolean) extends Predicate[Option[A]] {

    def validate(value: Option[A]): Result = value match {
      case None =>
        if (validNone) Right(Chunk(ValidationError.EqualToNone())) else Left(Chunk(ValidationError.EqualToNone()))
      case Some(v) => Validation(pred).validate(v).map(_ => Chunk.empty)
    }
  }

  final case class Contramap[B, A](pred: Bool[Predicate[A]], f: (B => A)) extends Predicate[B] {
    def validate(value: B): Result = Validation(pred).validate(f(value)).map(_ => Chunk.empty)
  }

  final case class Either[L, R](left: Bool[Predicate[L]], right: Bool[Predicate[R]])
      extends Predicate[scala.util.Either[L, R]] {

    def validate(value: scala.util.Either[L, R]): Result = value match {
      case scala.util.Left(l)  => Validation(left).validate(l).map(_ => Chunk.empty)
      case scala.util.Right(r) => Validation(right).validate(r).map(_ => Chunk.empty)
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy