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

validator.Extractor.scala Maven / Gradle / Ivy

The newest version!
package validator

import scala.annotation.tailrec
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds

final case class Extractor[A](name: ValidationName, extract: String => Either[ValidationError, A]) extends Validation[A] {
  def apply(value: String): ValidationResult[A] = {
    extract(value) match {
      case Right(x) => ValidationSuccess(x)
      case Left(e) => ValidationFailure.of(name -> Seq(e))
    }
  }
}

final case class OptionExtractor[A](a: Validation[A]) extends Validation[Option[A]] {
  def name = a.name

  override def run(params: Map[String, String]): ValidationResult[Option[A]] = {
    findValue(params) match {
      case Nil =>
        ValidationSuccess(None)
      case value +: _ =>
        apply(value)
    }
  }
  
  def apply(value: String): ValidationResult[Option[A]] = {
    a(value).map(Some(_))
  }
}

final case class SeqExtractor[C[_], A](a: Validation[A],
                                       cbf: CanBuildFrom[Nothing, A, C[A]]) extends Validation[C[A]] {
  def name = a.name

  def indexes(key: String, data: Map[String, String]): Seq[Int] = {
    val KeyPattern = ("^" + java.util.regex.Pattern.quote(key) + """\[(\d+)\].*$""").r
    data.toSeq.collect { case (KeyPattern(index), _) => index.toInt }.sorted.distinct
  }

  override def findValue(params: Map[String, String]): Seq[String] = {
    indexes(name, params).flatMap { i => params.get(s"$name[$i]") }
  }

  override def run(params: Map[String, String]): ValidationResult[C[A]] = {
    val xs: Seq[ValidationResult[A]] = findValue(params).map(a.apply)

    @tailrec
    def f(ys: Seq[ValidationResult[A]],
          i: Int,
          su: Seq[A],
          fa: Seq[ValidationResult.Error]): (Seq[A], Seq[ValidationResult.Error]) = {
      ys match {
        case ValidationSuccess(h) +: t =>
          f(t, i + 1, h +: su, fa)
        case ValidationFailure((name, e) +: _) +: t =>
          f(t, i + 1, su, (s"$name[$i]", e) +: fa)
        case Nil =>
          (su.reverse, fa.reverse)
      }
    }
    f(xs, 0, Nil, Nil) match {
      case (su, Nil) =>
        ValidationSuccess((cbf() ++= su).result)
      case (_, Seq(fa @ _*)) =>
        ValidationFailure(fa)
    }
  }
  
  def apply(value: String): ValidationResult[C[A]] = {
    val builder = cbf.apply
    a.apply(value).map { x =>
      builder += x
      builder.result
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy