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 |