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

.circumflex-orm.1.2.source-code.validation.scala Maven / Gradle / Ivy

package ru.circumflex.orm

import _root_.ru.circumflex.core._
import java.lang.String

// ## Validation

case class ValidationError(val source: String,
                           val errorKey: String,
                           var params: Map[String, String]) {
  def this(source: String, errorKey: String, params: Pair[String, String]*) =
    this(source, errorKey, Map(params: _*))

  val fullKey = source + "." + errorKey
  params += "src" -> source

  protected def toMsg(key: String, messages: Messages): String = messages.get(key, params) match {
    case Some(msg) => msg
    case _ =>
      val i = key.indexOf(".")
      if (i == -1) key
      else toMsg(key.substring(i + 1), messages)
  }
  def toMsg(messages: Messages): String = toMsg(fullKey, messages)
  def toMsg: String = toMsg(CircumflexContext.get.messages)

  protected def matches(thisKey: String, key: String): Boolean =
    if (thisKey == key || thisKey + "." + errorKey == key) true
    else {
      val i = thisKey.indexOf(".")
      if (i == -1) false
      else matches(thisKey.substring(i + 1), key)
    }

  def matches(key: String): Boolean = matches(source, key)

  override def hashCode = source.hashCode * 31 + errorKey.hashCode
  override def equals(that: Any) = that match {
    case e: ValidationError => e.source == this.source && e.errorKey == this.errorKey
    case _ => false
  }

  override def toString = fullKey
}

trait ValidationErrorGroup extends HashModel {
  def errors: Seq[ValidationError]
  def get(key: String): Option[Seq[ValidationError]] = Some(errors.filter(e => e.matches(key)))
  override def toString = errors.map(_.toString).mkString(", ")
}

class ValidationErrors(var errors: ValidationError*) extends ValidationErrorGroup {
  def toException = new ValidationException(errors: _*)
}

class ValidationException(val errors: ValidationError*)
    extends CircumflexException("Validation failed.") with ValidationErrorGroup

class RecordValidator[R <: Record[R]] {
  protected var _validators: Seq[R => Option[ValidationError]] = Nil
  def validators = _validators
  def validate(record: R): Seq[ValidationError] =
    _validators.flatMap(_.apply(record)).toList.removeDuplicates
  def add(validator: R => Option[ValidationError]): this.type = {
    _validators ++= List(validator)
    return this
  }
  def addForInsert(validator: R => Option[ValidationError]): this.type =
    add(r => if (r.transient_?) validator(r) else None)
  def addForUpdate(validator: R => Option[ValidationError]): this.type =
    add(r => if (!r.transient_?) validator(r) else None)
  def notNull(f: R => Field[_]): this.type = add(r => {
    val field = f(r)
    if (field.null_?) Some(new ValidationError(field.uuid, "null")) else None
  })
  def notEmpty(f: R => TextField): this.type = add(r => {
    val field = f(r)
    if (field.null_?)
      Some(new ValidationError(field.uuid, "null"))
    else if (field.getValue.trim == "")
      Some(new ValidationError(field.uuid, "empty"))
    else None
  })
  def pattern(f: R => TextField, regex: String, key: String = "pattern"): this.type = add(r => {
    val field = f(r)
    if (field.null_?)
      None
    else if (!field.getValue.matches(regex))
      Some(new ValidationError(field.uuid, key, "regex" -> regex, "value" -> field.getValue))
    else None
  })
  def unique(f: R => Field[_], key: String = "unique"): this.type = addForInsert(r => {
    val field = f(r)
    r.relation.criteria.add(field EQ field()).unique.map(a => new ValidationError(field.uuid, key))
  })
  def uniqueAll(f: R => Seq[Field[_]], key: String = "unique"): this.type = addForInsert(r => {
    val fields = f(r)
    val crit = r.relation.criteria
    fields.foreach(f => crit.add(f EQ f()))
    crit.unique.map(a => new ValidationError(r.uuid, key))
  })
}







© 2015 - 2025 Weber Informatics LLC | Privacy Policy