init
This commit is contained in:
158
internal/validator/constants.go
Normal file
158
internal/validator/constants.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Package validator provides validation utilities for API parameters
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Pagination constants
|
||||
const (
|
||||
DefaultPageSize = 20
|
||||
MaxPageSize = 100
|
||||
MinPageSize = 1
|
||||
)
|
||||
|
||||
// Amount constants
|
||||
const (
|
||||
MinAmount = 0.01
|
||||
MaxAmount = 999999999999.99
|
||||
)
|
||||
|
||||
// Date constants
|
||||
const (
|
||||
MaxDateRangeDays = 366
|
||||
MaxFutureDays = 365
|
||||
)
|
||||
|
||||
// String length constants
|
||||
const (
|
||||
MaxNameLength = 100
|
||||
MaxNoteLength = 500
|
||||
)
|
||||
|
||||
// Validation errors
|
||||
var (
|
||||
ErrPaginationLimitExceeded = errors.New("pagination limit exceeded maximum allowed value")
|
||||
ErrInvalidOffset = errors.New("pagination offset cannot be negative")
|
||||
ErrAmountTooSmall = errors.New("amount is below minimum allowed value")
|
||||
ErrAmountTooLarge = errors.New("amount exceeds maximum allowed value")
|
||||
ErrDateRangeExceeded = errors.New("date range exceeds maximum allowed days")
|
||||
ErrFutureDateExceeded = errors.New("date exceeds maximum allowed future date")
|
||||
ErrEndDateBeforeStartDate = errors.New("end date must be after start date")
|
||||
ErrNameTooLong = errors.New("name exceeds maximum allowed length")
|
||||
ErrNoteTooLong = errors.New("note exceeds maximum allowed length")
|
||||
)
|
||||
|
||||
// ValidatePagination validates and normalizes pagination parameters
|
||||
// Returns normalized offset and limit values
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 7.1, 7.2
|
||||
func ValidatePagination(offset, limit int) (int, int) {
|
||||
// Normalize offset
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
// Normalize limit
|
||||
if limit <= 0 {
|
||||
limit = DefaultPageSize
|
||||
}
|
||||
if limit > MaxPageSize {
|
||||
limit = MaxPageSize
|
||||
}
|
||||
|
||||
return offset, limit
|
||||
}
|
||||
|
||||
// ValidatePaginationStrict validates pagination parameters and returns error if invalid
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 7.1, 7.2, 7.3
|
||||
func ValidatePaginationStrict(offset, limit int) error {
|
||||
if offset < 0 {
|
||||
return fmt.Errorf("%w: offset=%d", ErrInvalidOffset, offset)
|
||||
}
|
||||
if limit > MaxPageSize {
|
||||
return fmt.Errorf("%w: limit=%d, max=%d", ErrPaginationLimitExceeded, limit, MaxPageSize)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAmount validates that an amount is within acceptable bounds
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 8.1, 8.2, 8.3
|
||||
func ValidateAmount(amount float64) error {
|
||||
if amount < MinAmount {
|
||||
return fmt.Errorf("%w: amount=%.2f, min=%.2f", ErrAmountTooSmall, amount, MinAmount)
|
||||
}
|
||||
if amount > MaxAmount {
|
||||
return fmt.Errorf("%w: amount=%.2f, max=%.2f", ErrAmountTooLarge, amount, MaxAmount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RoundAmount rounds an amount to 2 decimal places
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 8.2
|
||||
func RoundAmount(amount float64) float64 {
|
||||
return math.Round(amount*100) / 100
|
||||
}
|
||||
|
||||
// ValidateDateRange validates that a date range is within acceptable bounds
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 9.1
|
||||
func ValidateDateRange(startDate, endDate time.Time) error {
|
||||
if endDate.Before(startDate) {
|
||||
return ErrEndDateBeforeStartDate
|
||||
}
|
||||
|
||||
days := int(endDate.Sub(startDate).Hours() / 24)
|
||||
if days > MaxDateRangeDays {
|
||||
return fmt.Errorf("%w: days=%d, max=%d", ErrDateRangeExceeded, days, MaxDateRangeDays)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateFutureDate validates that a date is not too far in the future
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 9.2
|
||||
func ValidateFutureDate(date time.Time) error {
|
||||
maxFutureDate := time.Now().AddDate(0, 0, MaxFutureDays)
|
||||
if date.After(maxFutureDate) {
|
||||
return fmt.Errorf("%w: date=%s, max=%s", ErrFutureDateExceeded, date.Format("2006-01-02"), maxFutureDate.Format("2006-01-02"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateStringLength validates that a string does not exceed the maximum length
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 10.1, 10.2
|
||||
func ValidateStringLength(s string, maxLen int, fieldName string) error {
|
||||
if len(s) > maxLen {
|
||||
if fieldName == "name" {
|
||||
return fmt.Errorf("%w: length=%d, max=%d", ErrNameTooLong, len(s), maxLen)
|
||||
}
|
||||
if fieldName == "note" {
|
||||
return fmt.Errorf("%w: length=%d, max=%d", ErrNoteTooLong, len(s), maxLen)
|
||||
}
|
||||
return fmt.Errorf("%s exceeds maximum length: length=%d, max=%d", fieldName, len(s), maxLen)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateName validates a name field
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 10.1
|
||||
func ValidateName(name string) error {
|
||||
return ValidateStringLength(name, MaxNameLength, "name")
|
||||
}
|
||||
|
||||
// ValidateNote validates a note field
|
||||
// Feature: api-interface-optimization
|
||||
// Validates: Requirements 10.2
|
||||
func ValidateNote(note string) error {
|
||||
return ValidateStringLength(note, MaxNoteLength, "note")
|
||||
}
|
||||
Reference in New Issue
Block a user