• Stars
    star
    29
  • Rank 860,307 (Top 17 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created over 10 years ago
  • Updated over 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Scala data validation library

Validation

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

Copyright 2014-16 Dave Gurnell. Licensed Apache 2.

Note: I'm working on a "sequel" to this library. Initial spikes are here.

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:

More Repositories

1

bridges

Generate bindings for Scala types in other programming languages.
Scala
56
star
2

unindent

Indent-adjusted multiline string literals for Scala.
Shell
48
star
3

checklist

Validation library for Scala.
Scala
47
star
4

bulletin

Automatically perform shallow merges on case classes. Treat your data with the latest updates!
Scala
42
star
5

meowsynth

The mighty meowing synthesizer!
Scala
30
star
6

typelevel-todomvc

Scala
25
star
7

atlas

A tiny embedded scripting language implemented in Scala.
Scala
24
star
8

shapeless-guide

The Type Astronaut's Guide to Shapeless
19
star
9

functional-data-validation

Slides and code samples for a talk on thinking functionally (and validating web forms).
Scala
18
star
10

99-ways-to-di

Slides from my lightning talk on Dependency Injection at Scala Central #5.
14
star
11

css-selector

Lift-style CSS selector transforms based on Scalate's Scuery
Scala
10
star
12

tipi

Tiny templating language written in Scala.
Scala
10
star
13

macros-vs-shapeless

Slides and code samples on meta-programming techniques in Scala.
Scala
10
star
14

spandoc

Write Pandoc filters in Scala.
Scala
7
star
15

scalalol-2011-talk

Slides and code samples for talk at Scala Lift-Off London 2011.
Scala
6
star
16

scala-opengl

Simple OpenGL examples using Scala, LWJGL, and sbt-lwjgl
Scala
6
star
17

shapeless-guide-slides

Slides for my Scala World 2016 workshop on shapeless.
6
star
18

smartypants

Simple smart constructor generation for Scala.
Scala
4
star
19

scalax2gether-2017

Workshop and hack proposals for the Scala Exchange Hack Day (ScalaX2gether 2017)
4
star
20

shapeless-sandbox

Scala
3
star
21

scalax-2014

Slides and code samples for my Scala Exchange 2014 talk on Functional Data Validation.
3
star
22

typelevel-philly-2016

3
star
23

sbt-less

Superseded by sbt-less in https://github.com/untyped/sbt-plugins.
Scala
3
star
24

akka-streams-case-study

Scala
2
star
25

poker-case-study

Poker hand comparison in Scala. A fairly advanced "Essential Scala" case study.
Scala
2
star
26

interpreter-case-study

Scala case study about building an interpreter and a simple DSL.
Scala
2
star
27

cats-error-case-study

Scala
2
star
28

bus-driver-case-study

Gossiping Bus Drivers Kata
Scala
2
star
29

scala-rpg-test

A sandbox project for playing with Scala and the graphics from Browserquest.
Scala
2
star
30

concurrency-case-study

Scala
2
star
31

versionit

Grab your Git commit hash as a Scala String.
Scala
2
star
32

advanced-scala-scalax15

Code written at Advanced Scala at Scala Exchange 2015
Scala
1
star
33

spectaskular-iphone

iPhone todo list app
Objective-C
1
star
34

brighton-java-sample-app

Scala talk for Brighton Java
CSS
1
star
35

session-cell

Cookie-based in-memory session storage for the Racket HTTP Server.
Scheme
1
star
36

kitties-case-study

Meow!
Scala
1
star
37

gilded-rose-case-study

Code refactoring kata
Scala
1
star
38

conway-case-study

Scala
1
star
39

mars-rover-case-study

Scala
1
star
40

asyncjs-creative-fp

Creative Functional Programming talk for AsyncJS.
1
star
41

parallel-case-study

Scala
1
star
42

bank-ocr-case-study

Scala
1
star
43

play-json-case-study

Scala
1
star
44

calc-case-study

Scala
1
star
45

bowling-case-study

Scala
1
star
46

advanced-scala

The old source code repository for Scala with Cats
1
star
47

paths-case-study

Essential Scala case study: selecting paths from a route finder service
Scala
1
star
48

typeclub

Scala
1
star
49

tagless-case-study

Scala
1
star
50

composejs

Javascript port of Compose (https://github.com/underscoreio/compose).
JavaScript
1
star
51

doodlejs

Javascript port of Doodle
JavaScript
1
star
52

fpinscala

My attempts at the exercises in Functional Programming in Scala.
Scala
1
star
53

shapeless-guide-code

The Type Astronaut's Guide to Shapeless (Example Code)
1
star
54

scaladays-berlin-2016

1
star
55

property-based-testing-workshop

Scala
1
star
56

advanced-scala-exercises

Scala
1
star
57

away-with-the-types

Scala
1
star
58

cats-effect-sandbox

An empty SBT project with dependencies on Cats and Cats Effect.
Scala
1
star