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.Path() if prefix != "" { prefix += ": " } return prefix + e.Err.Error() } func (e ValidationError) Path() string { path := e.Model if e.Field != "" { if len(path) > 0 { path += "." } path += e.Field } return path } func (e ValidationError) Type() ErrorType { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Type() } return ErrorTypeIncorrectInput } func (e ValidationError) Code() string { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Code() } 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.Path() if prefix != "" { prefix += ": " } return prefix + e.Err.Error() } func (e SliceElementValidationError) Path() string { path := e.Model if e.Field != "" { if len(path) > 0 { path += "." } path += e.Field + "[" + strconv.Itoa(e.Index) + "]" } return path } func (e SliceElementValidationError) Type() ErrorType { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Type() } return ErrorTypeIncorrectInput } func (e SliceElementValidationError) Code() string { var domainErr Error if errors.As(e.Err, &domainErr) { return domainErr.Code() } 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) Type() ErrorType { return ErrorTypeIncorrectInput } func (e MinGreaterEqualError) Code() 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) Type() ErrorType { return ErrorTypeIncorrectInput } func (e MaxLessEqualError) Code() 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) Type() ErrorType { return ErrorTypeIncorrectInput } func (e LenOutOfRangeError) Code() 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, } } type InvalidURLError struct { URL string } var _ ErrorWithParams = InvalidURLError{} func (e InvalidURLError) Error() string { return fmt.Sprintf("%s: invalid URL", e.URL) } func (e InvalidURLError) Type() ErrorType { return ErrorTypeIncorrectInput } func (e InvalidURLError) Code() string { return "invalid-url" } func (e InvalidURLError) Params() map[string]any { return map[string]any{ "URL": e.URL, } } var ErrRequired error = simpleError{ msg: "can't be blank", typ: ErrorTypeIncorrectInput, code: "required", } var ErrNil error = simpleError{ msg: "must not be nil", typ: ErrorTypeIncorrectInput, code: "nil", } var ErrInvalidCursor error = simpleError{ msg: "invalid cursor", typ: ErrorTypeIncorrectInput, code: "invalid-cursor", } 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 validateVersionCode(code string) error { return validateStringLen(code, versionCodeMinLength, versionCodeMaxLength) } func validateServerKey(key string) error { return validateStringLen(key, serverKeyMinLength, serverKeyMaxLength) } 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 }