This module contains a set of functions for data validation.
Wrap some value in Validation
Wrap in Validation data constructor
pure "John" == Validation <| Ok "John"Result extraction
Extract a Result from Validation
extract <| Validation <| Err "Wrong number" == Err "Wrong number"
extract <| Validation <| Ok "John" == Ok "John"Chaining computations
Chain together many computations that may failed.
val1 = Validation <| Ok "One"
val2 = Validation <| Ok "Two"
val3 = Validation <| Ok "Three"
res = val1
|> andThen (\v1 -> val2
|> andThen (\v2 -> val3
|> andThen (\v3 -> pure <| String.join " " [ v1, v2, v3 ]
)))
-- `res` is `Validation <| Ok "One Two Three"`Note that if one of the values in the chain is an error, the result will be the first error encountered. If you want to accumulate errors, then use the @withValidation function
type alias ValidatedPerson =
{ firstName : String
, lastName : String
, age : Integer
, email : String
, ipAddress : String
}
let
validatedFirstName = Validation <| Ok "John"
validatedLastName = Validation <| Err "The last name field is missing"
validatedAge = Validation <| Ok 40
validatedEmail = Validation <| Err "Invalid email: johnwick.com"
validatedIpAddress = Validation <| Ok "70.235.93.79"
res = validatedFirstName
|> andThen (\vFn -> validatedLastName
|> andThen (\fLn -> validatedAge
|> andThen (\vAge -> validatedEmail
|> andThen (\vEmail -> validatedIpAddress
|> andThen (\vIp -> pure <| ValidatedPerson vId vFn vLn vAge vEmail vIp
)))))
-- `res` is equal to `Validation <| Err "The last name field is missing"Chaining computations with error accumulation
Chain together many computations that may failed. Errors are stored in a list.
If you want to display only the first encountered error, use andThen.
If you don't want to work with lists, you can create your own function to do a chain of calculations. To do this, see the @applyOrCollect function
type alias ValidatedPerson =
{ firstName : String
, lastName : String
, age : Int
, email : String
, ipAddress : String
}
let firstName = Validation <| Ok "John"
lastName = Validation <| Ok "Wick"
age = Validation <| Ok 40
email = Validation <| Ok "[email protected]"
ip = Validation <| Ok "70.235.93.79"
res = pure ValidatedPerson
|> withValidation firstName
|> withValidation lastName
|> withValidation age
|> withValidation email
|> withValidation ip
-- `res` is equal to `Validation <| Ok <| ValidatedPerson { ... }If there are errors:
let firstName = Validation <| Ok "John"
lastName = Validation <| Ok "Wick"
age = Validation <| Err ["Invalid age"]
email = Validation <| Ok "[email protected]"
ip = Validation <| Err ["Invalid ip"]
res = pure ValidatedPerson
|> withValidation firstName
|> withValidation lastName
|> withValidation age
|> withValidation email
|> withValidation ip
-- `res` is equal to `Validation <| Err ["Invalid age", "Invalid ip"]Combines two validations into one, and gets an opportunity to
collect the errors with the given function.
This is preferable over andThen because you can collect errors.
typically usage trough withValidation, but applyOrCollect
is exposed to allow usage of different data structures. For example:
withValidationDict : Validation (Dict comparable e) (a -> b)
-> Validation (Dict comparable e) a
-> Validation (Dict comparable e) b
withValidationDict = applyOrCollect Dict.unionValidated value mapping
Mapping a validated value
map toUpper <| Validation <| Ok "John" == Validation <| Ok "JOHN"
map toUpper <| Validation <| Err "Wrong number" == Validation <| Err "Wrong Number"Error mapping
mapError toUpper <| Validation <| Err "Wrong number" == Validation <| Err "WRONG NUMBER"
mapError toUpper <| Validation <| Ok "John" == Validation <| Ok "John"Converting Validation to Maybe
toMaybe <| Validation <| Err ["The field age is missing"] == Nothing
toMaybe <| Validation <| Ok 48 == Just 48Converting Maybe to Validation
fromMaybe Nothing ["The age field is missing"] == Validation <| Err ["The field age is missing"]
fromMaybe (Just 48) ["The age field is missing"] == Validation <| Ok 48
A type like result but accumulates errors. normal usage would entail
map,pureandwithValidation.