1
|
|
|
// Copyright 2021 Igor Lazarev. All rights reserved. |
2
|
|
|
// Use of this source code is governed by a MIT-style |
3
|
|
|
// license that can be found in the LICENSE file. |
4
|
|
|
|
5
|
|
|
// Package validation provides tools for data validation. |
6
|
|
|
// It is designed to create complex validation rules with abilities to hook into the validation process. |
7
|
|
|
package validation |
8
|
|
|
|
9
|
|
|
import ( |
10
|
|
|
"context" |
11
|
|
|
) |
12
|
|
|
|
13
|
|
|
const DefaultGroup = "default" |
14
|
|
|
|
15
|
|
|
// Validatable is interface for creating validatable types on the client side. |
16
|
|
|
// By using it you can build complex validation rules on a set of objects used in other objects. |
17
|
|
|
// |
18
|
|
|
// Example |
19
|
|
|
// |
20
|
|
|
// type Book struct { |
21
|
|
|
// Title string |
22
|
|
|
// Author string |
23
|
|
|
// Keywords []string |
24
|
|
|
// } |
25
|
|
|
// |
26
|
|
|
// func (b Book) Validate(ctx context.Context, validator *validation.Validator) error { |
27
|
|
|
// return validator.Validate( |
28
|
|
|
// ctx, |
29
|
|
|
// validation.StringProperty("title", &b.Title, it.IsNotBlank()), |
30
|
|
|
// validation.StringProperty("author", &b.Author, it.IsNotBlank()), |
31
|
|
|
// validation.CountableProperty("keywords", len(b.Keywords), it.HasCountBetween(1, 10)), |
32
|
|
|
// validation.EachStringProperty("keywords", b.Keywords, it.IsNotBlank()), |
33
|
|
|
// ) |
34
|
|
|
// } |
35
|
|
|
type Validatable interface { |
36
|
|
|
Validate(ctx context.Context, validator *Validator) error |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
// ValidatableFunc is a functional adapter for the [Validatable] interface. |
40
|
|
|
type ValidatableFunc func(ctx context.Context, validator *Validator) error |
41
|
|
|
|
42
|
|
|
// Validate runs validation process on function. |
43
|
1 |
|
func (f ValidatableFunc) Validate(ctx context.Context, validator *Validator) error { |
44
|
|
|
return f(ctx, validator) |
45
|
1 |
|
} |
46
|
1 |
|
|
47
|
1 |
|
// Filter is used for processing the list of errors to return a single [ViolationList]. |
48
|
1 |
|
// If there is at least one non-violation error it will return it instead. |
49
|
|
|
func Filter(violations ...error) error { |
50
|
|
|
list := &ViolationList{} |
51
|
|
|
|
52
|
1 |
|
for _, violation := range violations { |
53
|
|
|
err := list.AppendFromError(violation) |
54
|
|
|
if err != nil { |
55
|
|
|
return err |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
return list.AsError() |
60
|
|
|
} |
61
|
|
|
|