Test Failed
Push — main ( 2d1ab0...e725b3 )
by Igor
01:52
created

validation_test.*UniqueBrandConstraint.ValidateBrand   A

Complexity

Conditions 4

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
dl 0
loc 24
rs 9.8
c 0
b 0
f 0
nop 2
1
package validation_test
2
3
import (
4
	"context"
5
	"fmt"
6
7
	"github.com/muonsoft/validation"
8
	"github.com/muonsoft/validation/validator"
9
)
10
11
type Brand struct {
12
	Name string
13
}
14
15
type BrandRepository struct {
16
	brands []Brand
17
}
18
19
func (repository *BrandRepository) FindByName(ctx context.Context, name string) ([]Brand, error) {
20
	found := make([]Brand, 0)
21
22
	for _, brand := range repository.brands {
23
		if brand.Name == name {
24
			found = append(found, brand)
25
		}
26
	}
27
28
	return found, nil
29
}
30
31
// To create your own functional argument for validation simply create a function with
32
// a typed value and use the validation.NewTypedArgument constructor.
33
func ValidBrand(brand *Brand, constraints ...validation.Constraint[*Brand]) validation.ValidatorArgument {
34
	return validation.NewTypedArgument[*Brand](brand, constraints...)
35
}
36
37
// UniqueBrandConstraint implements BrandConstraint.
38
type UniqueBrandConstraint struct {
39
	brands *BrandRepository
40
}
41
42
func (c *UniqueBrandConstraint) Validate(brand *Brand, scope validation.Scope) error {
43
	// usually, you should ignore empty values
44
	// to check for an empty value you should use it.NotBlankConstraint
45
	if brand == nil {
46
		return nil
47
	}
48
49
	// you can pass the context value from the scope
50
	brands, err := c.brands.FindByName(scope.Context(), brand.Name)
51
	// here you can return a service error so that the validation process
52
	// is stopped immediately
53
	if err != nil {
54
		return err
55
	}
56
	if len(brands) == 0 {
57
		return nil
58
	}
59
60
	// use the scope to build violation with translations
61
	return scope.
62
		BuildViolation("notUniqueBrand", `Brand with name "{{ name }}" already exists.`).
63
		// you can inject parameter value to the message here
64
		WithParameter("{{ name }}", brand.Name).
65
		Create()
66
}
67
68
func ExampleNewTypedArgument_customArgumentConstraintValidator() {
69
	repository := &BrandRepository{brands: []Brand{{"Apple"}, {"Orange"}}}
70
	isEntityUnique := &UniqueBrandConstraint{brands: repository}
71
72
	brand := Brand{Name: "Apple"}
73
74
	err := validator.Validate(
75
		// you can pass here the context value to the validation scope
76
		context.WithValue(context.Background(), exampleKey, "value"),
77
		ValidBrand(&brand, isEntityUnique),
78
	)
79
80
	fmt.Println(err)
81
	// Output:
82
	// violation: Brand with name "Apple" already exists.
83
}
84