Git Product home page Git Product logo

validation's Introduction

Validation

Copyright 2014 Dave Gurnell of Underscore

Licensed under the Apache License v2.0

Work-in-progress library demonstrating a functional programming approach to data validation in Scala.

Synopsis

scala> :paste
// Entering paste mode (ctrl-D to finish)

import io.underscore.validation._

case class Address(house: Int, street: String)
case class Person(name: String, age: Int, address: Address)
case class Business(name: String, addresses: Seq[Address])

implicit val addressValidator: Validator[Address] =
  validate[Address].
  field(_.house)(warn(gte(1))).
  field(_.street)(warn(nonEmpty))

implicit val personValidator: Validator[Person] =
  validate[Person].
  field(_.name)(nonEmpty).
  field(_.age)(gte(1)).
  field(_.address)

implicit val businessValidator: Validator[Business] =
  validate[Business].
  field(_.name)(nonEmpty).
  seqField(_.addresses)

// Exiting paste mode, now interpreting.

import io.underscore.validation._
defined class Address
defined class Person
defined class Business
addressValidator: io.underscore.validation.Validator[Address] = <function1>
personValidator: io.underscore.validation.Validator[Person] = <function1>
businessValidator: io.underscore.validation.Validator[Business] = <function1>

scala> Person("", 0, Address(0, "")).validate.prettyPrint
res0: String =
Validated Person(,0,Address(0,)):
 - Error: name - Must not be empty
 - Error: age - Must be 1 or higher
 - Warning: address.house - Must be 1 or higher
 - Warning: address.street - Must not be empty

Design

Validation is performed by instances of Validator[A], which is essentially a trait representing a function of signature:

A => Seq[ValidationResult]

where a ValidationResult represents a validation error or warning and encapsulates a message and a Javascript-accessor-like path:

scala> ValidationError("FAIL!") prefix 123 prefix "bar" prefix "foo"
res0: io.underscore.validation.ValidationError = 
  ValidationError(FAIL!,ValidationPath(foo.bar[123]))

scala> res0.message
res1: String = FAIL!

scala> res0.path.pathString
res2: String = foo.bar[123]

The library contains a DSL for constructing validators and using them to build other vaildators:

scala> gte(0) and lte(3)
res0: io.underscore.validation.Validator[Int] = <function1>

scala> required(res0)
res1: io.underscore.validation.Validator[Option[Int]] = <function1>

scala> res1(None)
res2: Seq[io.underscore.validation.ValidationResult] = List(
  ValidationError(Value is required,ValidationPath()))

scala> res1(Some(-1))
res3: Seq[io.underscore.validation.ValidationResult] = List(
  ValidationError(Must be 0 or higher,ValidationPath()))

Like validation results, validators can be assocated with specific paths into the data:

scala> res1 prefix "inner" prefix "outer"
res4: io.underscore.validation.Validator[Option[Int]] = <function1>

scala> res4(Some(4))
res5: Seq[io.underscore.validation.ValidationResult] = List(
  ValidationError(Must be 3 or lower,ValidationPath(outer.inner)))

The library makes use of Scala macros in certain places to automatically capture path information from the names of accessors used to drill down into data:

scala> case class Address(house: Int, street: String)
defined class Address

scala> validate[Address].
     | field(_.house)(gte(1)).
     | field(_.street)(warn(nonEmpty))
res0: io.underscore.validation.Validator[Address] = <function1>

scala> res0(Address(-1, ""))
res1: Seq[io.underscore.validation.ValidationResult] = List(
  ValidationError(Must be 1 or higher,ValidationPath(house)),
  ValidationWarning(Must not be empty,ValidationPath(street)))

Contributors

Many thanks to the following for their contributions:

validation's People

Watchers

Jai avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.