alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Play Framework/Scala example source code file (JsConstraints.scala)

This example Play Framework source code file (JsConstraints.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Play Framework (and Scala) source code examples by using tags.

All credit for the original source code belongs to Play Framework; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Play Framework tags/keywords

a, api, boolean, format, json, jspath, jssuccess, jsvalue, library, m, owrites, play, play framework, reads, validation, writes

The JsConstraints.scala Play Framework example source code

/*
 * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
 */
package play.api.libs.json

import play.api.data.validation.ValidationError
import Json._

trait ConstraintFormat {
  def of[A](implicit fmt: Format[A]): Format[A] = fmt

  /** deleted because useless and troublesome (better to use nullable anyway) */
  //def optional[A](implicit fmt: Format[A]): Format[Option[A]] = Format[Option[A]]( Reads.optional(fmt), Writes.optional(fmt) )

  def optionWithNull[A](implicit fmt: Format[A]): Format[Option[A]] = Format[Option[A]](Reads.optionWithNull(fmt), Writes.optionWithNull(fmt))
}

trait PathFormat {
  def at[A](path: JsPath)(implicit f: Format[A]): OFormat[A] =
    OFormat[A](Reads.at(path)(f), Writes.at(path)(f))

  def nullable[A](path: JsPath)(implicit f: Format[A]): OFormat[Option[A]] =
    OFormat(Reads.nullable(path)(f), Writes.nullable(path)(f))

}

trait PathReads {

  def required(path: JsPath)(implicit reads: Reads[JsValue]): Reads[JsValue] = at(path)(reads)

  def at[A](path: JsPath)(implicit reads: Reads[A]): Reads[A] =
    Reads[A](js => path.asSingleJsResult(js).flatMap(reads.reads(_).repath(path)))

  /**
   * Reads a Option[T] search optional or nullable field at JsPath (field not found or null is None
   * and other cases are Error).
   *
   * It runs through JsValue following all JsPath nodes on JsValue except last node:
   * - If one node in JsPath is not found before last node => returns JsError( "missing-path" )
   * - If all nodes are found till last node, it runs through JsValue with last node =>
   *   - If last node if not found => returns None
   *   - If last node is found with value "null" => returns None
   *   - If last node is found => applies implicit Reads[T]
   */
  def nullable[A](path: JsPath)(implicit reads: Reads[A]) = Reads[Option[A]] { json =>
    path.applyTillLast(json).fold(
      jserr => jserr,
      jsres => jsres.fold(
        _ => JsSuccess(None),
        a => a match {
          case JsNull => JsSuccess(None)
          case js => reads.reads(js).repath(path).map(Some(_))
        }
      )
    )
  }

  def jsPick[A <: JsValue](path: JsPath)(implicit reads: Reads[A]): Reads[A] = at(path)(reads)

  def jsPickBranch[A <: JsValue](path: JsPath)(implicit reads: Reads[A]): Reads[JsObject] =
    Reads[JsObject](js => path.asSingleJsResult(js).flatMap { jsv => reads.reads(jsv).repath(path) }.map(jsv => JsPath.createObj(path -> jsv)))

  def jsPut(path: JsPath, a: => JsValue) = Reads[JsObject](json => JsSuccess(JsPath.createObj(path -> a)))

  def jsCopyTo[A <: JsValue](path: JsPath)(reads: Reads[A]) =
    Reads[JsObject](js => reads.reads(js).map(js => JsPath.createObj(path -> js)))

  def jsUpdate[A <: JsValue](path: JsPath)(reads: Reads[A]) =
    Reads[JsObject](js => js match {
      case o: JsObject =>
        path.asSingleJsResult(o)
          .flatMap(js => reads.reads(js).repath(path))
          .map(jsv => JsPath.createObj(path -> jsv))
          .map(opath => o.deepMerge(opath))
      case _ =>
        JsError(JsPath(), ValidationError("error.expected.jsobject"))
    })

  def jsPrune(path: JsPath) = Reads[JsObject](js => path.prune(js))
}

trait ConstraintReads {
  /** The simpler of all Reads that just finds an implicit Reads[A] of the expected type */
  def of[A](implicit r: Reads[A]) = r

  /** deleted because useless and troublesome (better to use nullable anyway) */
  //def optional[A](implicit reads:Reads[A]):Reads[Option[A]] =
  //  Reads[Option[A]](js => JsSuccess(reads.reads(js).asOpt))

  /** very simple optional field Reads that maps "null" to None */
  def optionWithNull[T](implicit rds: Reads[T]): Reads[Option[T]] = Reads(js => js match {
    case JsNull => JsSuccess(None)
    case js => rds.reads(js).map(Some(_))
  })

  /** Stupidly reads a field as an Option mapping any error (format or missing field) to None */
  def optionNoError[A](implicit reads: Reads[A]): Reads[Option[A]] =
    Reads[Option[A]](js => JsSuccess(reads.reads(js).asOpt))

  def list[A](implicit reads: Reads[A]): Reads[List[A]] = Reads.traversableReads[List, A]
  def set[A](implicit reads: Reads[A]): Reads[Set[A]] = Reads.traversableReads[Set, A]
  def seq[A](implicit reads: Reads[A]): Reads[Seq[A]] = Reads.traversableReads[Seq, A]
  def map[A](implicit reads: Reads[A]): Reads[collection.immutable.Map[String, A]] = Reads.mapReads[A]

  /**
   * Defines a minimum value for a numeric Reads. Combine with `max` using `or`, e.g.
   * `.read(Reads.min(0) or Reads.max(100))`.
   */
  def min[N](m: N)(implicit reads: Reads[N], num: Numeric[N]) =
    filterNot[N](ValidationError("error.min", m))(num.lt(_, m))(reads)

  /**
   * Defines a maximum value for a numeric Reads. Combine with `min` using `or`, e.g.
   * `.read(Reads.min(0.1) or Reads.max(1.0))`.
   */
  def max[N](m: N)(implicit reads: Reads[N], num: Numeric[N]) =
    filterNot[N](ValidationError("error.max", m))(num.gt(_, m))(reads)

  def filterNot[A](error: ValidationError)(p: A => Boolean)(implicit reads: Reads[A]) =
    Reads[A](js => reads.reads(js).filterNot(error)(p))

  def filter[A](otherwise: ValidationError)(p: A => Boolean)(implicit reads: Reads[A]) =
    Reads[A](js => reads.reads(js).filter(otherwise)(p))

  def minLength[M](m: Int)(implicit reads: Reads[M], p: M => scala.collection.TraversableLike[_, M]) =
    filterNot[M](ValidationError("error.minLength", m))(_.size < m)

  def maxLength[M](m: Int)(implicit reads: Reads[M], p: M => scala.collection.TraversableLike[_, M]) =
    filterNot[M](ValidationError("error.maxLength", m))(_.size > m)

  /**
   * Defines a regular expression constraint for `String` values, i.e. the string must match the regular expression pattern
   */
  def pattern(regex: => scala.util.matching.Regex, error: String = "error.pattern")(implicit reads: Reads[String]) =
    Reads[String](js => reads.reads(js).flatMap { o =>
      regex.unapplySeq(o).map(_ => JsSuccess(o)).getOrElse(JsError(error))
    })

  def email(implicit reads: Reads[String]): Reads[String] =
    pattern("""\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b""".r, "error.email")

  def verifying[A](cond: A => Boolean)(implicit rds: Reads[A]) =
    filter[A](ValidationError("error.invalid"))(cond)(rds)

  def verifyingIf[A](cond: A => Boolean)(subreads: Reads[_])(implicit rds: Reads[A]) =
    Reads[A] { js =>
      rds.reads(js).flatMap { t =>
        (scala.util.control.Exception.catching(classOf[MatchError]) opt cond(t)).flatMap { b =>
          if (b) Some(subreads.reads(js).map(_ => t))
          else None
        }.getOrElse(JsSuccess(t))
      }
    }

  def pure[A](a: => A) = Reads[A] { js => JsSuccess(a) }

}

trait PathWrites {
  def at[A](path: JsPath)(implicit wrs: Writes[A]): OWrites[A] =
    OWrites[A] { a => JsPath.createObj(path -> wrs.writes(a)) }

  /**
   * writes a optional field in given JsPath : if None, doesn't write field at all.
   * Please note we do not write "null" but simply omit the field when None
   * If you want to write a "null", use ConstraintWrites.optionWithNull[A]
   */
  def nullable[A](path: JsPath)(implicit wrs: Writes[A]): OWrites[Option[A]] =
    OWrites[Option[A]] { a =>
      a match {
        case Some(a) => JsPath.createObj(path -> wrs.writes(a))
        case None => Json.obj()
      }
    }

  def jsPick(path: JsPath): Writes[JsValue] =
    Writes[JsValue] { obj => path(obj).headOption.getOrElse(JsNull) }

  def jsPickBranch(path: JsPath): OWrites[JsValue] =
    OWrites[JsValue] { obj => JsPath.createObj(path -> path(obj).headOption.getOrElse(JsNull)) }

  def jsPickBranchUpdate(path: JsPath, wrs: OWrites[JsValue]): OWrites[JsValue] =
    OWrites[JsValue] { js =>
      JsPath.createObj(
        path -> path(js).headOption.flatMap(js => js.asOpt[JsObject].map(obj => obj.deepMerge(wrs.writes(obj)))).getOrElse(JsNull)
      )
    }

  def pure[A](path: JsPath, fixed: => A)(implicit wrs: Writes[A]): OWrites[JsValue] =
    OWrites[JsValue] { js => JsPath.createObj(path -> wrs.writes(fixed)) }

}

trait ConstraintWrites {
  def of[A](implicit w: Writes[A]) = w

  // deleted because troublesome...
  // def optional[A](implicit wa: Writes[A]): Writes[Option[A]] = Writes[Option[A]] { a => a match {
  //  case None => Json.obj()
  //  case Some(av) => wa.writes(av)
  //}}

  def pure[A](fixed: => A)(implicit wrs: Writes[A]): Writes[JsValue] =
    Writes[JsValue] { js => wrs.writes(fixed) }

  def pruned[A](implicit w: Writes[A]): Writes[A] = new Writes[A] {
    def writes(a: A): JsValue = JsUndefined("pruned")
  }

  def list[A](implicit writes: Writes[A]): Writes[List[A]] = Writes.traversableWrites[A]
  def set[A](implicit writes: Writes[A]): Writes[Set[A]] = Writes.traversableWrites[A]
  def seq[A](implicit writes: Writes[A]): Writes[Seq[A]] = Writes.traversableWrites[A]
  def map[A](implicit writes: Writes[A]): OWrites[collection.immutable.Map[String, A]] = Writes.mapWrites[A]

  /**
   * Pure Option Writer[T] which writes "null" when None which is different
   * from `JsPath.writeNullable which omits the field when None
   */
  def optionWithNull[A](implicit wa: Writes[A]) = Writes[Option[A]] { a =>
    a match {
      case None => JsNull
      case Some(av) => wa.writes(av)
    }
  }
}

Other Play Framework source code examples

Here is a short list of links related to this Play Framework JsConstraints.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.