@@ -47,6 +47,11 @@ type Error struct {
47
47
// Origin should be set in the most deeply nested validation function that
48
48
// can still identify the unique source of the error.
49
49
Origin string
50
+
51
+ // CoveredByDeclarative is true when this error is covered by declarative
52
+ // validation. This field is to identify errors from imperative validation
53
+ // that should also be caught by declarative validation.
54
+ CoveredByDeclarative bool
50
55
}
51
56
52
57
var _ error = & Error {}
@@ -116,6 +121,12 @@ func (e *Error) WithOrigin(o string) *Error {
116
121
return e
117
122
}
118
123
124
+ // MarkCoveredByDeclarative marks the error as covered by declarative validation.
125
+ func (e * Error ) MarkCoveredByDeclarative () * Error {
126
+ e .CoveredByDeclarative = true
127
+ return e
128
+ }
129
+
119
130
// ErrorType is a machine readable value providing more detail about why
120
131
// a field is invalid. These values are expected to match 1-1 with
121
132
// CauseType in api/types.go.
@@ -189,32 +200,32 @@ func (t ErrorType) String() string {
189
200
190
201
// TypeInvalid returns a *Error indicating "type is invalid"
191
202
func TypeInvalid (field * Path , value interface {}, detail string ) * Error {
192
- return & Error {ErrorTypeTypeInvalid , field .String (), value , detail , "" }
203
+ return & Error {ErrorTypeTypeInvalid , field .String (), value , detail , "" , false }
193
204
}
194
205
195
206
// NotFound returns a *Error indicating "value not found". This is
196
207
// used to report failure to find a requested value (e.g. looking up an ID).
197
208
func NotFound (field * Path , value interface {}) * Error {
198
- return & Error {ErrorTypeNotFound , field .String (), value , "" , "" }
209
+ return & Error {ErrorTypeNotFound , field .String (), value , "" , "" , false }
199
210
}
200
211
201
212
// Required returns a *Error indicating "value required". This is used
202
213
// to report required values that are not provided (e.g. empty strings, null
203
214
// values, or empty arrays).
204
215
func Required (field * Path , detail string ) * Error {
205
- return & Error {ErrorTypeRequired , field .String (), "" , detail , "" }
216
+ return & Error {ErrorTypeRequired , field .String (), "" , detail , "" , false }
206
217
}
207
218
208
219
// Duplicate returns a *Error indicating "duplicate value". This is
209
220
// used to report collisions of values that must be unique (e.g. names or IDs).
210
221
func Duplicate (field * Path , value interface {}) * Error {
211
- return & Error {ErrorTypeDuplicate , field .String (), value , "" , "" }
222
+ return & Error {ErrorTypeDuplicate , field .String (), value , "" , "" , false }
212
223
}
213
224
214
225
// Invalid returns a *Error indicating "invalid value". This is used
215
226
// to report malformed values (e.g. failed regex match, too long, out of bounds).
216
227
func Invalid (field * Path , value interface {}, detail string ) * Error {
217
- return & Error {ErrorTypeInvalid , field .String (), value , detail , "" }
228
+ return & Error {ErrorTypeInvalid , field .String (), value , detail , "" , false }
218
229
}
219
230
220
231
// NotSupported returns a *Error indicating "unsupported value".
@@ -229,15 +240,15 @@ func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *E
229
240
}
230
241
detail = "supported values: " + strings .Join (quotedValues , ", " )
231
242
}
232
- return & Error {ErrorTypeNotSupported , field .String (), value , detail , "" }
243
+ return & Error {ErrorTypeNotSupported , field .String (), value , detail , "" , false }
233
244
}
234
245
235
246
// Forbidden returns a *Error indicating "forbidden". This is used to
236
247
// report valid (as per formatting rules) values which would be accepted under
237
248
// some conditions, but which are not permitted by current conditions (e.g.
238
249
// security policy).
239
250
func Forbidden (field * Path , detail string ) * Error {
240
- return & Error {ErrorTypeForbidden , field .String (), "" , detail , "" }
251
+ return & Error {ErrorTypeForbidden , field .String (), "" , detail , "" , false }
241
252
}
242
253
243
254
// TooLong returns a *Error indicating "too long". This is used to report that
@@ -251,7 +262,7 @@ func TooLong(field *Path, value interface{}, maxLength int) *Error {
251
262
} else {
252
263
msg = "value is too long"
253
264
}
254
- return & Error {ErrorTypeTooLong , field .String (), "<value omitted>" , msg , "" }
265
+ return & Error {ErrorTypeTooLong , field .String (), "<value omitted>" , msg , "" , false }
255
266
}
256
267
257
268
// TooLongMaxLength returns a *Error indicating "too long".
@@ -279,14 +290,14 @@ func TooMany(field *Path, actualQuantity, maxQuantity int) *Error {
279
290
actual = omitValue
280
291
}
281
292
282
- return & Error {ErrorTypeTooMany , field .String (), actual , msg , "" }
293
+ return & Error {ErrorTypeTooMany , field .String (), actual , msg , "" , false }
283
294
}
284
295
285
296
// InternalError returns a *Error indicating "internal error". This is used
286
297
// to signal that an error was found that was not directly related to user
287
298
// input. The err argument must be non-nil.
288
299
func InternalError (field * Path , err error ) * Error {
289
- return & Error {ErrorTypeInternal , field .String (), nil , err .Error (), "" }
300
+ return & Error {ErrorTypeInternal , field .String (), nil , err .Error (), "" , false }
290
301
}
291
302
292
303
// ErrorList holds a set of Errors. It is plausible that we might one day have
@@ -313,6 +324,14 @@ func (list ErrorList) WithOrigin(origin string) ErrorList {
313
324
return list
314
325
}
315
326
327
+ // MarkCoveredByDeclarative marks all errors in the list as covered by declarative validation.
328
+ func (list ErrorList ) MarkCoveredByDeclarative () ErrorList {
329
+ for _ , err := range list {
330
+ err .CoveredByDeclarative = true
331
+ }
332
+ return list
333
+ }
334
+
316
335
// ToAggregate converts the ErrorList into an errors.Aggregate.
317
336
func (list ErrorList ) ToAggregate () utilerrors.Aggregate {
318
337
if len (list ) == 0 {
@@ -349,3 +368,25 @@ func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList {
349
368
// FilterOut takes an Aggregate and returns an Aggregate
350
369
return fromAggregate (err .(utilerrors.Aggregate ))
351
370
}
371
+
372
+ // ExtractCoveredByDeclarative returns a new ErrorList containing only the errors that should be covered by declarative validation.
373
+ func (list ErrorList ) ExtractCoveredByDeclarative () ErrorList {
374
+ newList := ErrorList {}
375
+ for _ , err := range list {
376
+ if err .CoveredByDeclarative {
377
+ newList = append (newList , err )
378
+ }
379
+ }
380
+ return newList
381
+ }
382
+
383
+ // RemoveCoveredByDeclarative returns a new ErrorList containing only the errors that should not be covered by declarative validation.
384
+ func (list ErrorList ) RemoveCoveredByDeclarative () ErrorList {
385
+ newList := ErrorList {}
386
+ for _ , err := range list {
387
+ if ! err .CoveredByDeclarative {
388
+ newList = append (newList , err )
389
+ }
390
+ }
391
+ return newList
392
+ }
0 commit comments