Skip to content

Instantly share code, notes, and snippets.

@zeroidentidad
Created February 13, 2025 17:20
Show Gist options
  • Select an option

  • Save zeroidentidad/b940d0501ff9a90b46fd4d20744816d8 to your computer and use it in GitHub Desktop.

Select an option

Save zeroidentidad/b940d0501ff9a90b46fd4d20744816d8 to your computer and use it in GitHub Desktop.

Revisions

  1. zeroidentidad created this gist Feb 13, 2025.
    157 changes: 157 additions & 0 deletions validation.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,157 @@
    package validate

    import (
    "fmt"
    "regexp"
    )

    type Errors map[string][]string

    func (e Errors) Add(field string, msg string) {
    AddError(field, e, msg)
    }

    var EmailRx = regexp.MustCompile(`^\S+@\S+$`)

    type Lengthable[Q any, U comparable] interface {
    []Q | map[U]Q
    }

    type NumericComparable interface {
    int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
    }

    // Validate records the provided error, if not nil, inside the errors list
    // marked against the provided field.
    func AddError(field string, errors Errors, msg string) {
    errors[field] = append(errors[field], msg)
    }

    // StringLength Checks that a string has either an exact count of characters,
    // or fits within the specified range of m to n (inclusive).
    func IsStringLength(
    field string,
    errors Errors,
    v string,
    m int,
    n int,
    ) {
    var msg string
    if m == n {
    msg = fmt.Sprintf("Must be exactly %d characters long", m)
    } else {
    msg = fmt.Sprintf("Must be between %d and %d characters long", m, n)
    }

    if len(v) < m || len(v) > n {
    AddError(field, errors, msg)
    }
    }

    // IsStringMinLength Checks that a string is at least the listed size.
    func IsStringMinLength(
    field string,
    errors Errors,
    v string,
    m int,
    ) {
    if len(v) < m {
    AddError(field, errors, fmt.Sprintf("Must be at least %d characters long", m))
    }
    }

    // NumberBetween Checks that the integer typed variable is exactly m == n in
    // size, or between m and n inclusive.
    func IsNumberBetween[T NumericComparable](
    field string,
    errors Errors,
    v T,
    m T,
    n T,
    ) {
    var msg string

    if m == n {
    msg = fmt.Sprintf("Must be exactly %d, but was %d", m, v)
    } else {
    msg = fmt.Sprintf("Must be between %d and %d, but was %d", m, n, v)
    }

    if v < m || v > n {
    AddError(field, errors, msg)
    }
    }

    func IsNotEmpty(
    field string,
    errors Errors,
    v string,
    ) {
    if len(v) == 0 {
    AddError(field, errors, "Must not be empty")
    }
    }

    // Size checks that an array or map has either exactly m == n entries, or
    // between m and n entries (inclusive)
    func IsSize[T Lengthable[Q, U], Q any, U comparable](
    field string,
    errors Errors,
    v T,
    m int,
    n int,
    ) {
    var msg string
    if m == n {
    msg = fmt.Sprintf("Must have exactly %d entries, but had %d", m, len(v))
    } else {
    msg = fmt.Sprintf("Must have between %d and %d entries, but had %d", m, n, len(v))
    }

    if len(v) < m || len(v) > n {
    AddError(field, errors, msg)
    }
    }

    // MinSize checks that an array or map has at least n entries
    func IsMinSize[T Lengthable[Q, U], Q any, U comparable](
    field string,
    errors Errors,
    v T,
    n int,
    ) {
    entry := "entry"
    if n > 1 {
    entry = "entries"
    }

    var msg string
    msg = fmt.Sprintf("Must have a minimum of %d %s, but had %d", n, entry, len(v))

    if len(v) < n {
    AddError(field, errors, msg)
    }
    }

    // Regex Confirms that value matches the provided regex
    func IsRegex(
    field string,
    errors Errors,
    v string,
    rx *regexp.Regexp,
    message string,
    ) {
    if !rx.MatchString(v) {
    AddError(field, errors, message)
    }
    }

    // Email Confirms that value matches our provided email regex. For a custom
    // email regex, use Regex.
    func IsEmail(
    field string,
    errors Errors,
    v string,
    ) {
    IsRegex(field, errors, v, EmailRx, "Email address is invalid")
    }