Created
June 13, 2014 04:32
-
-
Save cwmyers/e07e706436fe4a7c92ef to your computer and use it in GitHub Desktop.
Validation Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.rea-group.validation | |
import scalaz._, Scalaz._ | |
import java.lang.NumberFormatException | |
import scala.collection.mutable.ListBuffer | |
object ValidationExample { | |
val suburbs = Map(3000 -> "Melbourne", 3121 -> "Richmond", 4000 -> "Brisbane", 2001 -> "Sydney") | |
def postCodeLookup(postCode: Int) = suburbs.get(postCode) | |
def isDigits(input: String): Boolean = input.matches("^[0-9]+$") | |
def createSuccessString(firstName: String, lastName: String, postCode: String, phoneNumber: String): String = | |
s"Validation succeed: $firstName $lastName of postcode $postCode has phone number $phoneNumber" | |
def createErrorString(errors: List[String]) = s"Failed to validate with the following errors: " + errors.mkString(", ") | |
// Old skool way of doing validations | |
def validateOldSkool(input: Map[String, String]): String = { | |
val errors = scala.collection.mutable.ListBuffer[String]() | |
val firstName = input.getOrElse("firstName", "") | |
if (firstName.isEmpty) | |
errors += "first name can't be empty" | |
val lastName = input.getOrElse("lastName", "") | |
if (lastName.isEmpty) | |
errors += "last name can't be empty" | |
val homePhone = input.getOrElse("homePhone", "") | |
var hasHomePhone = false | |
val phoneErrors = ListBuffer[String]() | |
if (!isDigits(homePhone)) { | |
phoneErrors += "Home phone needs to be digits" | |
} else { | |
hasHomePhone = true | |
} | |
val mobilePhone = input.getOrElse("mobilePhone", "") | |
var hasMobilePhone = false | |
if (!hasHomePhone) { | |
if (!isDigits(mobilePhone)) { | |
phoneErrors += "mobile phone needs to be digits" | |
} else { | |
hasMobilePhone = true | |
} | |
} | |
if (!hasHomePhone && !hasMobilePhone) | |
errors ++= phoneErrors | |
val phone = if (hasHomePhone) homePhone else mobilePhone | |
val postCode = input.getOrElse("postCode", "") | |
var postCodeInt = 0 | |
var suburb = "" | |
try { | |
postCodeInt = Integer.parseInt(postCode) | |
val maybeSuburb: Option[String] = postCodeLookup(postCodeInt) | |
if (maybeSuburb.isDefined) | |
suburb = maybeSuburb.get | |
else | |
errors += "You don't live in a valid postcode area" | |
} catch { | |
case e: NumberFormatException => errors += "post code must be a number" | |
} | |
if (errors.isEmpty) { | |
createSuccessString(firstName, lastName, postCode, phone) | |
} else { | |
createErrorString(errors.toList) | |
} | |
} | |
// no skool like the new skool | |
def validate(input: Map[String, String]): String = { | |
val validatedFirstName = validateInput(input, "firstName").flatMap(firstName => validateName("first name", firstName)) | |
val validatedLastName = validateInput(input, "lastName").flatMap(lastName => validateName("last name", lastName)) | |
val validatedSuburb = validateInput(input, "postCode") | |
.flatMap(postCode => postCode.parseInt.leftMap(_ => "post code must be a number").toValidationNel) | |
.flatMap(postCode => postCodeLookup(postCode).toSuccess("not in a valid area").toValidationNel) | |
val mobilePhone = validatePhone(input, "mobilePhone", "mobile phone") | |
val homePhone = validatePhone(input, "homePhone", "home phone") | |
val validatedPhone = mobilePhone orElse homePhone | |
val successStringOrListOfErrors = accumulate(createSuccessString)(validatedFirstName, validatedLastName, validatedSuburb, validatedPhone) | |
successStringOrListOfErrors.valueOr(errors => createErrorString(errors.list)) | |
} | |
def validateInput(input: Map[String, String], key: String) = input.get(key).toSuccess(s"Could not find $key").toValidationNel | |
def validatePhone(input: Map[String, String], key: String, label: String): ValidationNel[String, String] = | |
validateInput(input, key).flatMap { | |
phone => | |
if (isDigits(phone)) phone.successNel else s"$label needs to be digits".failNel | |
} | |
def validateName(label: String, name: String): ValidationNel[String, String] = | |
if (!name.isEmpty) name.successNel else s"$label can't be empty".failNel | |
type V[X] = ValidationNel[String, X] | |
def accumulate[A, B, C, D, E](f: (A, B, C, D) => E) = Applicative[V].lift4(f) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment