Skip to main content

Validation

Validation runs before every insert and update, and a failure stops the write. It runs at the same point as hooks, so bulk writes skip it, and so does ant.WithoutHooks.

A Validate method​

For rules that span fields, give the model a Validate method.

type Signup struct {
ID int64
Name string
Email string
Age int
}

func (s *Signup) Validate(ctx context.Context) error {
if s.Name == "" {
return errors.New("name is required")
}

return nil
}

Field rules​

b.Validate attaches a rule to a single field, typed to that field. The validate package has the common ones ready to go.

func (Signup) Configure(b *ant.ModelBuilder[Signup]) {
b.Validate(&S.Name, validate.All(validate.Required[string](), validate.MaxLength(50)))
b.Validate(&S.Email, validate.Email)
b.Validate(&S.Age, validate.Range(0, 150))
}

var S = ant.Fields[Signup]()
RuleChecks
validate.Required[V]()Not the zero value
validate.EmailA valid address
validate.MinLength(n), validate.MaxLength(n)String length
validate.Range(low, high)Between two values
validate.OneOf(a, b, c)One of these
validate.Matches(pattern)Matches a *regexp.Regexp
validate.All(rules...)All of them

A rule is just a func(V) error, so writing your own is easy.

Reading the error​

A failed rule comes back as an ant.ValidationError, which tells you the field.

err := db.Signups.Insert(ctx, &Signup{Email: "a@example.com"})

var invalid *ant.ValidationError

if errors.As(err, &invalid) {
fmt.Println(invalid.Field, invalid.Err) // Name, and why
}