package domain import ( "errors" "fmt" "strconv" ) type ValidationError struct { Model string Field string Err error } var _ ErrorWithParams = ValidationError{} func (e ValidationError) Error() string { prefix := e.Model if e.Field != "" { if len(prefix) > 0 { prefix += "." } prefix += e.Field } if prefix != "" { prefix += ": " } return prefix + e.Err.Error() } func (e ValidationError) Code() ErrorCode { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Code() } return ErrorCodeIncorrectInput } func (e ValidationError) Slug() string { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Slug() } return "validation-failed" } func (e ValidationError) Params() map[string]any { var withParams ErrorWithParams if ok := errors.As(e.Err, &withParams); !ok { return nil } return withParams.Params() } func (e ValidationError) Unwrap() error { return e.Err } type SliceElementValidationError struct { Model string Field string Index int Err error } var _ ErrorWithParams = SliceElementValidationError{} func (e SliceElementValidationError) Error() string { prefix := e.Model if e.Field != "" { if len(prefix) > 0 { prefix += "." } prefix += e.Field + "[" + strconv.Itoa(e.Index) + "]" } if prefix != "" { prefix += ": " } return prefix + e.Err.Error() } func (e SliceElementValidationError) Code() ErrorCode { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Code() } return ErrorCodeIncorrectInput } func (e SliceElementValidationError) Slug() string { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Slug() } return "slice-element-validation-failed" } func (e SliceElementValidationError) Params() map[string]any { var withParams ErrorWithParams if ok := errors.As(e.Err, &withParams); !ok { return nil } return withParams.Params() } func (e SliceElementValidationError) Unwrap() error { return e.Err } type MinGreaterEqualError struct { Min int Current int } var _ ErrorWithParams = MinGreaterEqualError{} func (e MinGreaterEqualError) Error() string { return fmt.Sprintf("must be no less than %d (current: %d)", e.Min, e.Current) } func (e MinGreaterEqualError) Code() ErrorCode { return ErrorCodeIncorrectInput } func (e MinGreaterEqualError) Slug() string { return "min-greater-equal" } func (e MinGreaterEqualError) Params() map[string]any { return map[string]any{ "Min": e.Min, "Current": e.Current, } } type MaxLessEqualError struct { Max int Current int } var _ ErrorWithParams = MaxLessEqualError{} func (e MaxLessEqualError) Error() string { return fmt.Sprintf("must be no greater than %d (current: %d)", e.Max, e.Current) } func (e MaxLessEqualError) Code() ErrorCode { return ErrorCodeIncorrectInput } func (e MaxLessEqualError) Slug() string { return "max-less-equal" } func (e MaxLessEqualError) Params() map[string]any { return map[string]any{ "Max": e.Max, "Current": e.Current, } } type LenOutOfRangeError struct { Min int Max int Current int } var _ ErrorWithParams = LenOutOfRangeError{} func (e LenOutOfRangeError) Error() string { return fmt.Sprintf("length must be between %d and %d (current length: %d)", e.Min, e.Max, e.Current) } func (e LenOutOfRangeError) Code() ErrorCode { return ErrorCodeIncorrectInput } func (e LenOutOfRangeError) Slug() string { return "length-out-of-range" } func (e LenOutOfRangeError) Params() map[string]any { return map[string]any{ "Min": e.Min, "Max": e.Max, "Current": e.Current, } } var ErrRequired error = simpleError{ msg: "can't be blank", code: ErrorCodeIncorrectInput, slug: "required", } var ErrNil error = simpleError{ msg: "must not be nil", code: ErrorCodeIncorrectInput, slug: "nil", } func validateSliceLen[S ~[]E, E any](s S, min, max int) error { if l := len(s); l > max || l < min { return LenOutOfRangeError{ Min: min, Max: max, Current: l, } } return nil } func validateStringLen(s string, min, max int) error { if l := len(s); l > max || l < min { return LenOutOfRangeError{ Min: min, Max: max, Current: l, } } return nil } func validateServerKey(key string) error { if l := len(key); l < serverKeyMinLength || l > serverKeyMaxLength { return LenOutOfRangeError{ Min: serverKeyMinLength, Max: serverKeyMaxLength, Current: l, } } return nil } func validateVersionCode(code string) error { if l := len(code); l < versionCodeMinLength || l > versionCodeMaxLength { return LenOutOfRangeError{ Min: versionCodeMinLength, Max: versionCodeMaxLength, Current: l, } } return nil } func validateIntInRange(current, min, max int) error { if current < min { return MinGreaterEqualError{ Min: min, Current: current, } } if current > max { return MaxLessEqualError{ Max: max, Current: current, } } return nil }