Current section
Files
Jump to
Current section
Files
src/valguard.gleam
import gleam/list
import gleam/result
/// Key/Value pair for encoding validation errors.
/// Key indicates the name of the field that failed validation
/// and Value is the error message.
pub type ValidationError {
ValidationError(key: String, value: String)
}
/// Takes a validation result and list of validation errors
/// If result is error, it adds it to the list
pub fn append_error(
result: Result(Nil, ValidationError),
list: List(ValidationError),
) -> List(ValidationError) {
case result {
Error(validation_error) -> {
list.append(list, [validation_error])
}
Ok(Nil) -> list
}
}
/// Takes a list of validation results and returns a list of the errors
/// Returns an empty list if no errors
pub fn collect_errors(
inputs: List(Result(Nil, ValidationError)),
) -> List(ValidationError) {
// filter for errors
list.filter_map(inputs, fn(x) {
case x {
Ok(Nil) -> Error(Nil)
Error(validation_error) -> Ok(validation_error)
}
})
}
/// Takes a list of validation errors and converts it to a result
/// Returns ok if list is empty
pub fn prepare(
errors: List(ValidationError),
) -> Result(Nil, List(ValidationError)) {
case list.is_empty(errors) {
True -> Ok(Nil)
False -> Error(errors)
}
}
/// Takes a list of validation errors and converts it to a result
/// wrapping the errors in a custom type. Returns Ok(Nil) if list is empty.
///
/// This functions similar to `valguard.prepare`.
pub fn prepare_with(
errors: List(ValidationError),
custom_type,
) -> Result(Nil, custom_type) {
case list.is_empty(errors) {
True -> Ok(Nil)
False -> Error(custom_type(errors))
}
}
/// Wrap list of errors from a Validation Result in a custom type.
@deprecated("Function will be removed in next release. If needed, you can implement it yourself.")
pub fn wrap_result(
result: Result(Nil, List(ValidationError)),
custom_type,
) -> Result(Nil, custom_type) {
result.map_error(result, fn(errors) { custom_type(errors) })
}
/// Validates a single validation function
@deprecated("Use function `with` instead")
pub fn single(
key: String,
validation_result: Result(Nil, String),
) -> Result(Nil, ValidationError) {
case validation_result {
Ok(Nil) -> Ok(Nil)
Error(value) -> Error(ValidationError(key:, value:))
}
}
/// Validates a list of requirements lazily.
///
/// Takes a key and list of validation functions.
///
/// Returns Ok(Nil) if success or Error(String) at first issue
pub fn list(
key: String,
list: List(fn() -> Result(Nil, String)),
) -> Result(Nil, ValidationError) {
// recursively check list of validations
case list_inner(list, Ok(Nil)) {
Ok(Nil) -> Ok(Nil)
Error(value) -> Error(ValidationError(key:, value:))
}
}
/// Inner recursive loop for list
fn list_inner(
list: List(fn() -> Result(Nil, String)),
prev: Result(Nil, String),
) -> Result(Nil, String) {
// return early if previous value was error
use _ <- result.try(prev)
case list {
[] -> prev
[next, ..rest] -> list_inner(rest, next())
}
}
/// Validates a list of requirements lazily.
///
/// Takes a key, value and list of validation functions.
///
/// Runs validation functions lazily and returns the result.
/// Returns Ok(Nil) if success or Error(String) at first issue
pub fn with(
key: String,
value,
list: List(fn(value) -> Result(Nil, String)),
) -> Result(Nil, ValidationError) {
// recursively check list of validations
case with_inner(list, value, Ok(Nil)) {
Ok(Nil) -> Ok(Nil)
Error(value) -> Error(ValidationError(key:, value:))
}
}
/// Inner recursive loop for with
fn with_inner(
list: List(fn(value) -> Result(Nil, String)),
value,
prev: Result(Nil, String),
) -> Result(Nil, String) {
// return early if previous value was error
use _ <- result.try(prev)
case list {
[] -> prev
[next, ..rest] -> with_inner(rest, value, next(value))
}
}