diff --git a/src/FSharpPlus/Data/Validation.fs b/src/FSharpPlus/Data/Validation.fs index 9813553fa..a341d6a3b 100644 --- a/src/FSharpPlus/Data/Validation.fs +++ b/src/FSharpPlus/Data/Validation.fs @@ -244,7 +244,6 @@ module Validation = coll1.Close (), coll2.Close () #endif - type Validation<'err,'a> with // as Applicative diff --git a/src/FSharpPlus/Extensions/Validators.fs b/src/FSharpPlus/Extensions/Validators.fs new file mode 100644 index 000000000..8b3ea60b4 --- /dev/null +++ b/src/FSharpPlus/Extensions/Validators.fs @@ -0,0 +1,75 @@ +namespace FSharpPlus + +[] +module RequiredValidation = + open System + open FSharpPlus.Data + + let inline private validate error f v = + if f v then + Success v + else + Failure [ error ] + + let inline notNullOrWhiteSpace error value = + validate (error value) (String.IsNullOrWhiteSpace >> not) value + + let inline greaterThan error min value = + validate (error value) (flip (>) min) value + + let inline greaterOrEqualThan error min value = + validate (error value) (flip (>=) min) value + + let inline email error value = + let check (v: string) = + try + let _ = Net.Mail.MailAddress(v) + true + with + | ex -> false + + validate (error value) check value + + let inline guidNotEmpty error value = + validate (error value) (fun v -> v <> Guid.Empty) value + + let inline object error value = + let check value = box value <> null + validate (error value) check + + let inline whenSome value checkWhenSome = + match value with + | Some v -> checkWhenSome v |> Validation.map Some + | _ -> Success None + + let inline arrayValues values check = + let validated : Validation<_,_> [] = + values + |> Array.map check + validated + |> sequence + |> Validation.map Seq.toArray + + let inline listValues values check = + let validated : List> = + values + |> List.map check + validated + |> sequence + |> Validation.map Seq.toArray + + let inline atLeastOne error = + let check values = + Seq.isEmpty values |> not + + validate error check + + let isSuccess = + function + | Success _ -> true + | Failure _ -> false + + let isFailure = + function + | Success _ -> false + | Failure _ -> true \ No newline at end of file diff --git a/src/FSharpPlus/FSharpPlus.fsproj b/src/FSharpPlus/FSharpPlus.fsproj index 832af9215..55c73255b 100644 --- a/src/FSharpPlus/FSharpPlus.fsproj +++ b/src/FSharpPlus/FSharpPlus.fsproj @@ -102,6 +102,7 @@ + diff --git a/tests/FSharpPlus.Tests/Validations.fs b/tests/FSharpPlus.Tests/Validations.fs index 34515a3f8..a03cf5f02 100644 --- a/tests/FSharpPlus.Tests/Validations.fs +++ b/tests/FSharpPlus.Tests/Validations.fs @@ -11,7 +11,17 @@ module Validation = open FSharpPlus.Data open Validation open FSharpPlus.Tests.Helpers - + + let private getSuccess = + function + | Success s -> s + | Failure _ -> failwith "It's a failure" + + let private getFailure = + function + | Success _ -> failwith "It's a Success" + | Failure f -> f + let fsCheck s x = Check.One({Config.QuickThrowOnFailure with Name = s}, x) module FunctorP = [] @@ -337,4 +347,53 @@ module Validation = let v: Validation = Success (async {return 42}) let r = Validation.bisequence v let subject = Async.RunSynchronously r - areStEqual subject (Success 42) \ No newline at end of file + areStEqual subject (Success 42) + + [] + [] + [] + [] + [] + let testValidateRequireString (str, success) = + let error = konst "Str" + let r = RequiredValidation.string error str + areStEqual (RequiredValidation.isSuccess r) success + + if not success then + let failure = getFailure r + areStEqual failure.Length 1 + areStEqual failure.[0] (error "") + else + () + + [] + [] + [] + [] + let testValidateRequireGreaterThan (value, limit, success) = + let error = konst "Int" + let r = RequiredValidation.greaterThan error limit value + areStEqual (RequiredValidation.isSuccess r) success + + if not success then + let failure = getFailure r + areStEqual failure.Length 1 + areStEqual failure.[0] (error 1) + else + () + + [] + [] + [] + [] + let testValidateRequireGreaterOrEqualThan (value, limit, success) = + let error = konst "Int" + let r = RequiredValidation.greaterOrEqualThan error limit value + areStEqual (RequiredValidation.isSuccess r) success + + if not success then + let failure = getFailure r + areStEqual failure.Length 1 + areStEqual failure.[0] (error 1) + else + () \ No newline at end of file