| Copyright | (c) digitally induced GmbH 2020 | 
|---|---|
| Safe Haskell | None | 
| Language | Haskell2010 | 
IHP.ValidationSupport.ValidateField
Description
Use validateField and validateFieldIO together with the validation functions to do simple validations.
Also take a look at validateIsUnique for e.g. checking that an email is unique.
Synopsis
- type Validator valueType = valueType -> ValidatorResult
- validateField :: forall (field :: Symbol) fieldValue model. (KnownSymbol field, HasField field model fieldValue, HasField "meta" model MetaBag, SetField "meta" model MetaBag) => Proxy field -> Validator fieldValue -> model -> model
- type ValidatorIO value = value -> IO ValidatorResult
- validateFieldIO :: forall (field :: Symbol) model fieldValue. (?modelContext :: ModelContext, KnownSymbol field, HasField field model fieldValue, HasField "meta" model MetaBag, SetField "meta" model MetaBag) => Proxy field -> ValidatorIO fieldValue -> model -> IO model
- validateMaybe :: (val -> ValidatorResult) -> Maybe val -> ValidatorResult
- withCustomErrorMessage :: Text -> (value -> ValidatorResult) -> value -> ValidatorResult
- validateAny :: [value -> ValidatorResult] -> value -> ValidatorResult
- validateAll :: [value -> ValidatorResult] -> value -> ValidatorResult
- nonEmpty :: IsEmpty value => value -> ValidatorResult
- isEmptyValue :: IsEmpty value => value -> ValidatorResult
- isPhoneNumber :: Text -> ValidatorResult
- isEmail :: Text -> ValidatorResult
- isInRange :: (Show value, Ord value) => (value, value) -> value -> ValidatorResult
- isLessThan :: (Show value, Ord value) => value -> value -> ValidatorResult
- isGreaterThan :: (Show value, Ord value) => value -> value -> ValidatorResult
- isEqual :: (Show value, Eq value) => value -> value -> ValidatorResult
- hasMaxLength :: Int -> Text -> ValidatorResult
- hasMinLength :: Int -> Text -> ValidatorResult
- isRgbHexColor :: Text -> ValidatorResult
- isRgbaHexColor :: Text -> ValidatorResult
- isHexColor :: Text -> ValidatorResult
- isRgbColor :: Text -> ValidatorResult
- isRgbaColor :: Text -> ValidatorResult
- isColor :: Text -> ValidatorResult
- isUrl :: Text -> ValidatorResult
- isInList :: (Eq value, Show value) => [value] -> value -> ValidatorResult
- isTrue :: Bool -> ValidatorResult
- isFalse :: Bool -> ValidatorResult
- matchesRegex :: Text -> Text -> ValidatorResult
- isSlug :: Text -> ValidatorResult
Documentation
type Validator valueType = valueType -> ValidatorResult Source #
A function taking some value and returning a ValidatorResult
>>>Validator TextText -> ValidatorResult
>>>Validator IntInt -> ValidatorResult
validateField :: forall (field :: Symbol) fieldValue model. (KnownSymbol field, HasField field model fieldValue, HasField "meta" model MetaBag, SetField "meta" model MetaBag) => Proxy field -> Validator fieldValue -> model -> model Source #
Validates a record field using a given validator function.
When the validation fails, the validation error is saved inside the meta :: MetaBag field of the record.
 You can retrieve a possible validation error using getValidationFailure.
Example: nonEmpty validation for a record
let project :: Project = newRecord
project
    |> validateField #name nonEmpty
    |> getValidationFailure #name -- Just "This field cannot be empty"
project
    |> set #name "Hello World"
    |> validateField #name nonEmpty
    |> getValidationFailure #name -- NothingExample: Using ifValid for branching
let project :: Project = newRecord
project
    |> validateField #name nonEmpty
    |> ifValid \case
        Left project -> do
            putStrLn "Invalid project. Please try again"
        Right project -> do
            putStrLn "Project is valid. Saving to database."
            createRecord projecttype ValidatorIO value = value -> IO ValidatorResult Source #
A function taking some value and returning a 'IO ValidatorResult'
>>>ValidatorIO TextText -> IO ValidatorResult
>>>ValidatorIO IntInt -> IO ValidatorResult
validateFieldIO :: forall (field :: Symbol) model fieldValue. (?modelContext :: ModelContext, KnownSymbol field, HasField field model fieldValue, HasField "meta" model MetaBag, SetField "meta" model MetaBag) => Proxy field -> ValidatorIO fieldValue -> model -> IO model Source #
Validates a record field using a given validator function.
The same as validateField, but works with IO and can e.g. access the database.
When the validation fails, the validation error is saved inside the meta :: MetaBag field of the record.
 You can retrieve a possible validation error using getValidationFailure.
validateMaybe :: (val -> ValidatorResult) -> Maybe val -> ValidatorResult Source #
Validate a Maybe field.
Validate a Maybe field using a given validator function. >>> validateMaybe nonEmpty (Just "foo") Success
>>>validateMaybe nonEmpty (Just "")Failure "This field cannot be empty"
If the value is Nothing, the validation will succeed.
 >>> validateMaybe nonEmpty Nothing
 Success
This function is useful when you want to validate a field that is optional. >>> buildPost :: Post -> Post >>> buildPost post = post >>> |> validateField #title nonEmpty >>> -- Assuming sourceUrl is optional. >>> |> validateField #sourceUrl (validateMaybe nonEmpty)
withCustomErrorMessage :: Text -> (value -> ValidatorResult) -> value -> ValidatorResult Source #
Overrides the error message of a given validator function.
>>>(nonEmpty |> withCustomErrorMessage "Custom error message") ""Failure "Custom error message"
>>>(isEmail |> withCustomErrorMessage "We only accept valid email addresses") "not valid email"Failure "We only accept valid email addresses"
validateAny :: [value -> ValidatorResult] -> value -> ValidatorResult Source #
Validates that value passes at least one of the given validators
>>>"ihp@example.com" |> validateAny([isEmptyValue, isEmail])Success
>>>"" |> validateAny([isEmptyValue, isEmail])Success
>>>"no spam plz" |> validateAny([empty, isEmail])Failure "did not pass any validators"
validateAll :: [value -> ValidatorResult] -> value -> ValidatorResult Source #
Validates that value passes all of the given validators
In case of multiple failures, the first Failure is returned.
>>>2016 |> validateAll([isGreaterThan(1900), isLessThan(2020)])Success
>>>1899 |> validateAll([isGreaterThan(1900), isLessThan(2020)])Failure "has to be greater than 1900"
nonEmpty :: IsEmpty value => value -> ValidatorResult Source #
Validates that value is not empty
>>>nonEmpty "hello world"Success
>>>nonEmpty ""Failure "This field cannot be empty"
>>>nonEmpty (Just "hello")Success
>>>nonEmpty NothingFailure "This field cannot be empty"
isEmptyValue :: IsEmpty value => value -> ValidatorResult Source #
Validates that value is empty
>>>isEmptyValue "hello world"Failure "This field must be empty"
>>>ieEmptyValue ""Success
>>>isEmptyValue (Just "hello")Failure "This field must be empty"
>>>isEmptyValue NothingSuccess
isPhoneNumber :: Text -> ValidatorResult Source #
Validates that value looks like a phone number
Values needs to start with + and has to have atleast 5 characters
>>>isPhoneNumber "1337"Failure ".."
>>>isPhoneNumber "+49123456789"Success
isEmail :: Text -> ValidatorResult Source #
Validates that value is an email address
The validation is not meant to be compliant with RFC 822. Its purpose is to reject obviously invalid values without false-negatives.
>>>isEmail "marc@digitallyinduced.com"Success
>>>isEmail "marc@secret.digitallyinduced.com" -- subdomains are fineSuccess
>>>isEmail "ॐ@मणिपद्मे.हूँ"Success
>>>isEmail "marc@localhost" -- Although discouraged by ICANN, dotless TLDs are legal. See https://www.icann.org/news/announcement-2013-08-30-enSuccess
>>>isEmail "loremipsum"Failure "is not a valid email"
>>>isEmail "A@b@c@domain.com"Failure "is not a valid email"
isInRange :: (Show value, Ord value) => (value, value) -> value -> ValidatorResult Source #
Validates that value is between min and max
>>>isInRange (0, 10) 5Success
>>>isInRange (0, 10) 0Success
>>>isInRange (0, 10) 1337Failure "has to be between 0 and 10"
>>>let isHumanAge = isInRange (0, 100)>>>isHumanAge 22Success
isLessThan :: (Show value, Ord value) => value -> value -> ValidatorResult Source #
Validates that value is less than a max value
>>>isLessThan 10 5Success
>>>isLessThan 10 20Failure "has to be less than 10"
isGreaterThan :: (Show value, Ord value) => value -> value -> ValidatorResult Source #
Validates that value is greater than a min value
>>>isGreaterThan 10 20Success
>>>isGreaterThan 10 5Failure "has to be greater than 10"
isEqual :: (Show value, Eq value) => value -> value -> ValidatorResult Source #
Validates that value is equal to another value
>>>isEqual "foo" "foo"Success
>>>isEqual "foo" "bar"Failure "has to be equal to \"foo\""
hasMaxLength :: Int -> Text -> ValidatorResult Source #
Validates that value has a max length
>>>hasMaxLength 10 "IHP"Success
>>>hasMaxLength 2 "IHP"Failure "is longer than 2 characters"
hasMinLength :: Int -> Text -> ValidatorResult Source #
Validates that value has a min length
>>>hasMinLength 2 "IHP"Success
>>>hasMinLength 10 "IHP"Failure "is shorter than 10 characters"
isRgbHexColor :: Text -> ValidatorResult Source #
Validates that value is a hex-based rgb color string
>>>isRgbHexColor "#ffffff"Success
>>>isRgbHexColor "#fff"Success
>>>isRgbHexColor "rgb(0, 0, 0)"Failure "is not a valid rgb hex color"
isRgbaHexColor :: Text -> ValidatorResult Source #
Validates that value is a hex-based rgb color string
>>>isRgbaHexColor "#ffffffff"Success
>>>isRgbaHexColor "#ffff"Success
>>>isRgbaHexColor "rgb(0, 0, 0, 1)"Failure "is not a valid rgba hex color"
isHexColor :: Text -> ValidatorResult Source #
Validates that value is a hex-based rgb(a) color string
>>>isHexColor "#ffffff"Success
>>>isHexColor "#ffffffff"Success
>>>isHexColor "rgb(0, 0, 0)"Failure "is not a valid hex color"
isRgbColor :: Text -> ValidatorResult Source #
Validates that value is a rgb() color string
>>>isRgbColor "rgb(255, 0, 0)"Success
>>>isRgbColor "#f00"Failure "is not a valid rgb() color"
isRgbaColor :: Text -> ValidatorResult Source #
Validates that value is a rgba() color string
>>>isRgbaColor "rgb(255, 0, 0, 1.0)"Success
>>>isRgbaColor "#f00f"Failure "is not a valid rgba() color"
isColor :: Text -> ValidatorResult Source #
Validates that value is a hex-based or rgb(a) color string
>>>isColor "#ffffff"Success
>>>isColor "rgba(255, 0, 0, 0.5)"Success
>>>isColor "rgb(0, 0, 0)"Failure "is not a valid color"
isUrl :: Text -> ValidatorResult Source #
Validates string starts with http:// or https://
>>>isUrl "https://digitallyinduced.com"Success
>>>isUrl "digitallyinduced.com"Failure "URL must start with http:// or https://"
isTrue :: Bool -> ValidatorResult Source #
Validates that value is True
>>>isTrue TrueSuccess
>>>isTrue FalseFailure "This field cannot be false"
isFalse :: Bool -> ValidatorResult Source #
Validates that value is False
>>>isFalse FalseSuccess
>>>isFalse TrueFailure "This field cannot be true"
matchesRegex :: Text -> Text -> ValidatorResult Source #
Validates that value is matched by the regular expression
>>>matchesRegex "^[0-9]{4}$" "2016"Success
>>>matchesRegex "^[0-9]{4}$" "16"Failure "This field does not match the regular expression \"^[0-9]{4}$\""
>>>matchesRegex "[0-9]{4}" "xx2016xx"Success -- regex is missing ^ and $
isSlug :: Text -> ValidatorResult Source #
Validates that value is a valid slug
>>>isSlug "i-am-a-slug"Success
>>>isSlug "I-AM-A-Slug (Copy)"Failure "is not a valid slug (consisting of only letters, numbers, underscores or hyphens)"