@@ -27,19 +27,19 @@ func ForPointer[T, S any](getter PropertyGetter[*T, S]) PropertyRules[T, S] {
27
27
// [Transformer] is only called if [PropertyGetter] returns a non-zero value.
28
28
func Transform [T , N , S any ](getter PropertyGetter [T , S ], transform Transformer [T , N ]) PropertyRules [N , S ] {
29
29
return PropertyRules [N , S ]{
30
- getter : func (s S ) (transformed N , err error ) {
30
+ transformGetter : func (s S ) (transformed N , original any , err error ) {
31
31
v := getter (s )
32
32
if err != nil {
33
- return transformed , err
33
+ return transformed , nil , err
34
34
}
35
35
if isEmptyFunc (v ) {
36
- return transformed , emptyErr {}
36
+ return transformed , nil , emptyErr {}
37
37
}
38
38
transformed , err = transform (v )
39
39
if err != nil {
40
- return transformed , NewPropertyError ( "" , v , NewRuleError (err .Error (), ErrorCodeTransform ) )
40
+ return transformed , v , NewRuleError (err .Error (), ErrorCodeTransform )
41
41
}
42
- return transformed , nil
42
+ return transformed , v , nil
43
43
},
44
44
}
45
45
}
@@ -56,18 +56,21 @@ type Predicate[S any] func(S) bool
56
56
type PropertyGetter [T , S any ] func (S ) T
57
57
58
58
type internalPropertyGetter [T , S any ] func (S ) (v T , err error )
59
+ type internalTransformPropertyGetter [T , S any ] func (S ) (transformed T , original any , err error )
59
60
type emptyErr struct {}
60
61
61
62
func (emptyErr ) Error () string { return "" }
62
63
63
64
// PropertyRules is responsible for validating a single property.
64
65
type PropertyRules [T , S any ] struct {
65
- name string
66
- getter internalPropertyGetter [T , S ]
67
- steps []interface {}
68
- required bool
69
- omitEmpty bool
70
- isPointer bool
66
+ name string
67
+ getter internalPropertyGetter [T , S ]
68
+ transformGetter internalTransformPropertyGetter [T , S ]
69
+ steps []interface {}
70
+ required bool
71
+ omitEmpty bool
72
+ hideValue bool
73
+ isPointer bool
71
74
}
72
75
73
76
// Validate validates the property value using provided rules.
@@ -80,6 +83,9 @@ func (r PropertyRules[T, S]) Validate(st S) PropertyErrors {
80
83
)
81
84
propValue , skip , err := r .getValue (st )
82
85
if err != nil {
86
+ if r .hideValue {
87
+ err = err .HideValue ()
88
+ }
83
89
return err
84
90
}
85
91
if skip {
@@ -122,6 +128,9 @@ loop:
122
128
allErrors = append (allErrors , NewPropertyError (r .name , propValue , ruleErrors ... ))
123
129
}
124
130
if len (allErrors ) > 0 {
131
+ if r .hideValue {
132
+ allErrors = allErrors .HideValue ()
133
+ }
125
134
return allErrors
126
135
}
127
136
return nil
@@ -157,6 +166,11 @@ func (r PropertyRules[T, S]) OmitEmpty() PropertyRules[T, S] {
157
166
return r
158
167
}
159
168
169
+ func (r PropertyRules [T , S ]) HideValue () PropertyRules [T , S ] {
170
+ r .hideValue = true
171
+ return r
172
+ }
173
+
160
174
type stopOnErrorStep uint8
161
175
162
176
func (r PropertyRules [T , S ]) StopOnError () PropertyRules [T , S ] {
@@ -172,16 +186,26 @@ func appendSteps[T any](slice []interface{}, steps []T) []interface{} {
172
186
}
173
187
174
188
func (r PropertyRules [T , S ]) getValue (st S ) (v T , skip bool , errs PropertyErrors ) {
175
- v , err := r .getter (st )
189
+ var (
190
+ err error
191
+ originalValue any
192
+ )
193
+ if r .transformGetter != nil {
194
+ v , originalValue , err = r .transformGetter (st )
195
+ } else {
196
+ v , err = r .getter (st )
197
+ }
176
198
_ , isEmptyError := err .(emptyErr )
177
199
// Any error other than [emptyErr] is considered critical, we don't proceed with validation.
178
200
if err != nil && ! isEmptyError {
179
- if propErr , ok := err .(* PropertyError ); ok {
180
- // Make sure the name is set to the current property name.
181
- propErr .PropertyName = r .name
182
- return v , false , PropertyErrors {propErr }
201
+ // If the value was transformed, we need to set the property value to the original, pre-transformed one.
202
+ var propValue interface {}
203
+ if HasErrorCode (err , ErrorCodeTransform ) {
204
+ propValue = originalValue
205
+ } else {
206
+ propValue = v
183
207
}
184
- return v , false , PropertyErrors {NewPropertyError (r .name , nil , err )}
208
+ return v , false , PropertyErrors {NewPropertyError (r .name , propValue , err )}
185
209
}
186
210
isEmpty := isEmptyError || (! r .isPointer && isEmptyFunc (v ))
187
211
if r .required && isEmpty {
0 commit comments