Passed
Pull Request — main (#22)
by Igor
01:48
created

examples_custom_service_constraint_test.go   A

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 54
dl 0
loc 98
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A validation_test.*UniqueEntityConstraint.GetName 0 2 1
A validation_test.*UniqueEntityConstraint.ValidateString 0 24 5
A validation_test.ExampleValidator_Validate_customServiceConstraint 0 16 2
A validation_test.*EntityRepository.FindByName 0 18 5
A validation_test.*UniqueEntityConstraint.SetUp 0 2 1
1
package validation_test
2
3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
8
	"github.com/muonsoft/validation"
9
	"github.com/muonsoft/validation/it"
10
	"github.com/muonsoft/validation/validator"
11
)
12
13
type contextKey string
14
15
const exampleKey contextKey = "exampleKey"
16
17
type Entity struct {
18
	Name string
19
}
20
21
type EntityRepository struct {
22
	entities []Entity
23
}
24
25
func (repository *EntityRepository) FindByName(ctx context.Context, name string) ([]Entity, error) {
26
	contextValue, ok := ctx.Value(exampleKey).(string)
27
	if !ok {
28
		return nil, errors.New("context value missing")
29
	}
30
	if contextValue != "value" {
31
		return nil, errors.New("invalid context value")
32
	}
33
34
	found := make([]Entity, 0)
35
36
	for _, entity := range repository.entities {
37
		if entity.Name == name {
38
			found = append(found, entity)
39
		}
40
	}
41
42
	return found, nil
43
}
44
45
type UniqueEntityConstraint struct {
46
	repository *EntityRepository
47
}
48
49
func (c *UniqueEntityConstraint) SetUp(scope *validation.Scope) error {
50
	return nil
51
}
52
53
func (c *UniqueEntityConstraint) GetName() string {
54
	return "UniqueEntityConstraint"
55
}
56
57
func (c *UniqueEntityConstraint) ValidateString(value *string, scope validation.Scope) error {
58
	// usually, you should ignore empty values
59
	// to check for an empty value you should use it.NotBlankConstraint
60
	if value == nil || *value == "" {
61
		return nil
62
	}
63
64
	// you can pass the context value from the scope
65
	entities, err := c.repository.FindByName(scope.Context(), *value)
66
	// here you can return a service error so that the validation process
67
	// is stopped immediately
68
	if err != nil {
69
		return err
70
	}
71
	if len(entities) == 0 {
72
		return nil
73
	}
74
75
	// use the scope to build violation with translations
76
	return scope.
77
		BuildViolation("notUnique", `Entity with name "{{ name }}" already exists.`).
78
		// you can inject parameter value to the message here
79
		SetParameter("{{ name }}", *value).
80
		GetViolation()
81
}
82
83
func ExampleValidator_Validate_customServiceConstraint() {
84
	repository := &EntityRepository{entities: []Entity{{"camera"}, {"book"}}}
85
	isEntityUnique := &UniqueEntityConstraint{repository: repository}
86
87
	entity := Entity{Name: "book"}
88
	ctx := context.WithValue(context.Background(), exampleKey, "value")
89
90
	err := validator.Validate(
91
		// you can pass here the context value to the validation scope
92
		validation.Context(ctx),
93
		validation.String(&entity.Name, it.IsNotBlank(), isEntityUnique),
94
	)
95
96
	violations := err.(validation.ViolationList)
97
	for _, violation := range violations {
98
		fmt.Println(violation.Error())
99
	}
100
	// Output:
101
	// violation: Entity with name "book" already exists.
102
}
103