ValidateA module for organizing validations of data structures.
Allows standardized ways of checking for conditions, and keeps track of the location of errors by keeping a path to each error found. Thus, if you were validating the following datastructure:
{ foo = 3; bar = { snoo = 34.5; blue = Snoot - 6 } }One might end up with an error with the error path:
bar.blue.Snoot : value -6 <= bound 0
By convention, the validations for a type defined in module M appear in module M, and have their name prefixed by validate_. E.g., Int.validate_positive.
Here's an example of how you would use validate with a record:
type t =
{ foo : int
; bar : float
}
[@@deriving fields ~iterators:to_list]
let validate t =
let module V = Validate in
let w check = V.field check t in
Fields.to_list ~foo:(w Int.validate_positive) ~bar:(w Float.validate_non_negative)
|> V.of_list
;;And here's an example of how you would use it with a variant type:
type t =
| Foo of int
| Bar of (float * int)
| Snoo of Floogle.t
let validate = function
| Foo i -> V.name "Foo" (Int.validate_positive i)
| Bar p ->
V.name
"Bar"
(V.pair ~fst:Float.validate_positive ~snd:Int.validate_non_negative p)
| Snoo floogle -> V.name "Snoo" (Floogle.validate floogle)
;;The result of a validation. This effectively contains the list of errors, qualified by their location path
type ('a : any) check__portable = 'a -> t @ portableTo make function signatures easier to read.
and ('a : any) check = 'a -> tTo make function signatures easier to read.
(check[@mode portable]) can be read as "a check that returns a Validate.t at mode portable".
If you have f of type (check[@mode portable]), sometimes the type checker takes some convincing to treat it as a check, even though a returning-at-portable function is morally a subtype of a returning-at-nonportable function. Writing (fun x -> f x) should be enough to convert the (check[@mode portable]) into a check.
val pass : t @@ portableA result containing no errors.
val fail : Base.string -> t @ portable @@ portableA result containing a single error.
val fails : Base.string -> 'a -> ('a -> Base.Sexp.t) -> t @@ portableval fail_s : Base.Sexp.t -> t @ portable @@ portableThis can be used with the %sexp extension.
val failf : ('a, Base.unit, Base.string, t) Base.format4 -> 'a @@ portableLike sprintf or failwithf but produces a t instead of a string or exception.
val name : Base.string -> t -> t @@ portableExtends location path by one name.
val lazy_name : Base.string Base.Lazy.t -> t -> t @@ portableExtends location path by one lazy name, which will be forced only in the case of failure.
val name_list : Base.string -> t Base.list -> t @@ portableval lazy_name_list : Base.string Base.Lazy.t -> t Base.list -> t @@ portableval fail_fn : Base.string -> _ check @ portable @@ portablefail_fn err returns a function that always returns fail, with err as the error message. (Note that there is no pass_fn so as to discourage people from ignoring the type of the value being passed unconditionally irrespective of type.)
protect f x applies the validation f to x, catching any exceptions and returning them as errors.
try_with f runs f catching any exceptions and returning them as errors.
val result : t -> Base.unit Base.Or_error.t @@ portableval errors : t -> Base.string Base.list @@ portableReturns a list of formatted error strings, which include both the error message and the path to the error.
If the result contains any errors, then raises an exception with a formatted error message containing a message for every error.
val valid_or_error : 'a check -> 'a -> 'a Base.Or_error.t @@ portableReturns an error if validation fails.
val field :
'a 'record. 'a check ->
'record ->
([> `Read ], 'record, 'a) Base.Field.t_with_perm ->
t @@ portableUsed for validating an individual field. Should be used with Fields.to_list.
val field_direct :
'a 'record. 'a check ->
([> `Read ], 'record, 'a) Base.Field.t_with_perm ->
'record ->
'a ->
t @@ portableUsed for validating an individual field. Should be used with Fields.Direct.to_list.
val field_folder :
'a check ->
'record ->
t Base.list ->
([> `Read ], 'record, 'a) Base.Field.t_with_perm ->
t Base.list @@ portableCreates a function for use in a Fields.fold.
val portable_field_folder :
'a check__portable ->
'record ->
t Base.portable Base.list ->
([> `Read ], 'record, 'a) Base.Field.t_with_perm ->
t Base.portable Base.list @@ portableLike field_folder, but for producing a list of portable ts. It's marginally easier to use directly when folding over fields to produce a portable result.
val field_direct_folder :
'a check ->
(t Base.list ->
([> `Read ], 'record, 'a) Base.Field.t_with_perm ->
'record ->
'a ->
t Base.list)
Base.Staged.t @@ portableCreates a function for use in a Fields.Direct.fold.
Combines a list of validation functions into one that does all validations.
val of_result :
('a -> (Base.unit, Base.string) Base.Result.t) ->
'a check__portable @@ portableCreates a validation function from a function that produces a Result.t.
val of_error : ('a -> Base.unit Base.Or_error.t) -> 'a check @@ portableval booltest :
('a -> Base.bool) ->
if_false:Base.string ->
'a check @@ portableCreates a validation function from a function that produces a bool.
val lazy_booltest :
('a -> Base.bool) ->
if_false:Base.string Base.Lazy.t ->
'a check @@ portableCreates a validation function from a function that produces a bool. Forces the name only when validation fails.
Validation functions for particular data types.
Validates a list, naming each element by its position in the list (where the first position is 1, not 0).
val list :
name:('a -> Base.string) ->
'a check ->
'a Base.list check @@ portableValidates a list, naming each element using a user-defined function for computing the name.
val of_error_opt : Base.string Base.option -> t @ portable @@ portableval alist :
name:('a -> Base.string) ->
'b check ->
('a * 'b) Base.list check @@ portableValidates an association list, naming each element using a user-defined function for computing the name.
val bounded :
name:('a -> Base.string) ->
lower:'a Base.Maybe_bound.t ->
upper:'a Base.Maybe_bound.t ->
compare:('a -> 'a -> Base.int) ->
'a check__portable @@ portablemodule Infix : sig ... end