// 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") }