Skip to content

Numbers

num.Of converts a numeric field to the number configurator, num.Ptr — a pointer to a numeric field. Supported types are int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64 and named types based on them.

The arguments of the rules have the type of the field. Untyped constants fit any numeric type, a value of another type doesn't compile:

type Price int64

type Product struct {
    Stock    int
    Price    Price
    Rating   float32
    Discount *uint8
}

b.Field(&p.Stock).As(num.Of).Min(0)
b.Field(&p.Price).As(num.Of).AnyOfInterval(1, 1_000_000) // the arguments are Price
b.Field(&p.Rating).As(num.Of).Max(5)
b.Field(&p.Discount).As(num.Ptr).Max(90)                 // a nil Discount is skipped

var limit int32 = 10
b.Field(&p.Stock).As(num.Of).Max(limit) // doesn't compile: int32 isn't int
b.Field(&p.Discount).As(num.Of)         // doesn't compile: *uint8 isn't a number, use num.Ptr

Slices of numbers are converted by num.Slice: b.Slice(&p.Sizes).As(num.Slice).Each(func(e *num.BaseConfigurator[int]) { e.Min(1) }), see Slices.

Rules

Rule Fails when Message
Required() num.Of: the value is zero; num.Ptr: the value is absent Should be fulfilled
Min(n) the value is less than n Cannot be less than %v
Max(n) the value is greater than n Cannot be greater than %v
GreaterThan(n), LessThan(n) the value isn't greater / less than n Should be greater than %v, Should be less than %v
GreaterField(&m.X), LessField(&m.X) the value isn't greater / less than the value of the field X Should be greater than %v, Should be less than %v
MinField(&m.X), MaxField(&m.X) the value is less or greater than the value of the field X, see Rules on other fields Cannot be less than %v, Cannot be greater than %v
AnyOf(values...) the value isn't one of values Only %v values is allowed
AnyOfInterval(begin, end) the value is outside [begin, end], both ends are included Only interval[%v - %v] is allowed
Latitude(), Longitude() the value is outside [-90, 90] / [-180, 180] Should be latitude, Should be longitude
Custom(fn) fn returns errors your messages, see Custom rules
When(fn) — the next rules are applied only if fn returns true, see Conditions

Zero and absent

Zero is a valid value of a pointer: b.Field(&p.Discount).As(num.Ptr).Required() passes for a pointer to 0 and fails for nil. Use a pointer field when zero must be distinguished from "not set", e.g. in PATCH requests:

package main

import (
    "context"
    "fmt"

    "github.com/insei/valigo"
    "github.com/insei/valigo/rules/num"
)

type UpdateProduct struct {
    Stock *int
}

func main() {
    v := valigo.New()
    valigo.Configure[UpdateProduct](v, func(b valigo.Configurator[UpdateProduct], p *UpdateProduct) {
        b.Field(&p.Stock).As(num.Ptr).Min(0)
    })

    zero, negative := 0, -1
    fmt.Println(v.Validate(context.Background(), &UpdateProduct{}))
    fmt.Println(v.Validate(context.Background(), &UpdateProduct{Stock: &zero}))
    fmt.Println(v.Validate(context.Background(), &UpdateProduct{Stock: &negative}))
}

Output:

[]
[]
[Cannot be less than 0 (Stock: -1)]