Skip to main content
Version: 0.1.1

Numeric Constraints

Numeric validation rules in Pedantigo for validating integers, floating-point numbers, and other numeric types.

Range Constraints

min / max

Validates the numeric value is within the specified range (inclusive).

type Product struct {
// Price must be at least 0.01 and at most 999,999.99
Price float64 `json:"price" pedantigo:"required,min=0.01,max=999999.99"`
// Quantity must be between 1 and 1000
Quantity int `json:"quantity" pedantigo:"required,min=1,max=1000"`
}

Behavior:

  • Works with all numeric types (int, int8-64, uint, uint8-64, float32, float64)
  • Both bounds are inclusive
  • Empty/zero values skip validation (only required constraint enforces non-zero)
  • Comparison uses numeric value, not string representation

gt / gte / lt / lte

Validates numeric values with exclusive or inclusive comparison bounds.

  • gt=N - Greater than (exclusive, value must be greater than N)
  • gte=N - Greater than or equal (inclusive, value must be at least N)
  • lt=N - Less than (exclusive, value must be less than N)
  • lte=N - Less than or equal (inclusive, value must be at most N)
type SurveyRating struct {
// Rating must be strictly greater than 0
Score int `json:"score" pedantigo:"required,gt=0"`
// Confidence must be at least 0.5
Confidence float64 `json:"confidence" pedantigo:"required,gte=0.5"`
// Days until expiration must be less than 365
DaysUntilExpiry int `json:"days_until_expiry" pedantigo:"required,lt=365"`
// Discount percentage must be at most 50
DiscountPercent int `json:"discount_percent" pedantigo:"required,lte=50"`
}

Behavior:

  • gt and lt exclude the boundary value
  • gte and lte include the boundary value
  • Works with all numeric types
  • Useful for enforcing strict domain rules

Sign Constraints

positive

Validates that a numeric value is strictly greater than zero (> 0).

type BankAccount struct {
// Balance can be positive (credits) or zero, but not negative
Balance float64 `json:"balance" pedantigo:"required,positive"`
// Withdrawal amount must be positive
WithdrawalAmount float64 `json:"withdrawal_amount" pedantigo:"required,positive"`
}

Valid examples: 1, 0.01, 1000.50, 999999 Invalid examples: 0, -1, -0.01

Note: Use gte=0 if you want to allow zero values.

negative

Validates that a numeric value is strictly less than zero (< 0).

type TemperatureReading struct {
// Temperature below freezing point
BelowFreezing float64 `json:"below_freezing" pedantigo:"negative"`
// Temperature change (decrease)
TemperatureChange float64 `json:"temperature_change" pedantigo:"negative"`
}

Valid examples: -1, -0.01, -273.15, -999 Invalid examples: 0, 1, 0.01

Note: Use lte=0 if you want to allow zero values.

Divisibility

multiple_of

Validates that a numeric value is evenly divisible by the specified number.

type TimeSlot struct {
// Meeting duration in minutes must be divisible by 15
DurationMinutes int `json:"duration_minutes" pedantigo:"required,multiple_of=15"`
}

type ShoppingCart struct {
// Pack size: items must be divisible by 6 (half-dozen)
Quantity int `json:"quantity" pedantigo:"required,min=6,multiple_of=6"`
}

type PercentageDiscount struct {
// Discount must be in 5% increments
DiscountPercent float64 `json:"discount_percent" pedantigo:"required,min=0,max=100,multiple_of=5"`
}

Valid examples (for multiple_of=5): 0, 5, 10, 15, 20, 100 Invalid examples (for multiple_of=5): 1, 3, 7, 22, 103

Behavior:

  • Uses modulo operator (value % N == 0)
  • Works with integers and floating-point numbers
  • For floats, validates with high precision to handle floating-point arithmetic quirks

Precision Constraints

max_digits

Validates that a numeric value has at most N total digits (excluding the decimal point and sign).

type ProductSKU struct {
// Product code: maximum 8 digits
Code int64 `json:"code" pedantigo:"required,max_digits=8"`
}

type BudgetAmount struct {
// Budget: at most 10 total digits (e.g., 9,999,999,999.99)
Amount float64 `json:"amount" pedantigo:"required,max_digits=10"`
}

Examples (with max_digits=6):

  • Valid: 123456 (6 digits), 12345 (5 digits), 123.45 (5 digits)
  • Invalid: 1234567 (7 digits), 123456.78 (8 digits)

Behavior:

  • Counts only the numeric digits
  • Ignores decimal point, sign, and exponent notation
  • Useful for database column constraints or API limits

decimal_places

Validates that a numeric value has at most N decimal places (digits after decimal point).

type MoneyAmount struct {
// Price in USD: maximum 2 decimal places
Price float64 `json:"price" pedantigo:"required,decimal_places=2"`
}

type ExchangeRate struct {
// Exchange rate: at most 6 decimal places
Rate float64 `json:"rate" pedantigo:"required,min=0,decimal_places=6"`
}

type MeasurementValue struct {
// Measurement: at most 4 decimal places
Meters float64 `json:"meters" pedantigo:"required,decimal_places=4"`
}

Examples (with decimal_places=2):

  • Valid: 10.50, 5.1, 100 (0 decimals), 0.05
  • Invalid: 10.505 (3 decimals), 5.123 (3 decimals)

Behavior:

  • Counts digits after the decimal point
  • Integers (no decimal point) are considered to have 0 decimal places and always pass
  • Useful for currency, measurements, and financial calculations
  • Works with both int (implicitly 0 decimals) and float64

Special Values

disallow_inf_nan

Validates that a floating-point value is neither infinity nor NaN (Not a Number).

type SensorData struct {
// Sensor reading must be a valid number
Temperature float64 `json:"temperature" pedantigo:"required,disallow_inf_nan"`
// Altitude must be finite
Altitude float64 `json:"altitude" pedantigo:"required,disallow_inf_nan"`
}

type CalculationResult struct {
// Result of division must be a valid number
Result float64 `json:"result" pedantigo:"required,disallow_inf_nan"`
}

Valid examples: 0.0, 1.5, -273.15, 999999.99, -0.00001 Invalid examples: math.Inf(1), math.Inf(-1), math.NaN()

Behavior:

  • Only applies to float32 and float64 types
  • Rejects positive infinity, negative infinity, and NaN
  • Useful when calculations might produce invalid floating-point values
  • Common after division operations or mathematical functions

Combining Numeric Constraints

Numeric constraints can be combined to create powerful validation rules:

type BankAccount struct {
// Account balance: must be at least 0, at most 999 billion
Balance float64 `json:"balance" pedantigo:"required,min=0,max=999000000000,decimal_places=2"`
}

type AgeVerification struct {
// Age: must be between 18 and 150
Age int `json:"age" pedantigo:"required,min=18,max=150"`
}

type PercentageScore struct {
// Score: 0-100 with one decimal place
Score float64 `json:"score" pedantigo:"required,min=0,max=100,decimal_places=1"`
}

type RatingScale struct {
// 5-star rating: 1 to 5, in increments of 0.5
Rating float64 `json:"rating" pedantigo:"required,min=1,max=5,multiple_of=0.5"`
}

type PaymentAmount struct {
// Payment: at least 0.01, at most 999,999.99, exactly 2 decimal places
Amount float64 `json:"amount" pedantigo:"required,min=0.01,max=999999.99,decimal_places=2"`
}

type ApiKeyID struct {
// API key ID: exactly 32 digits, no sign
KeyID int64 `json:"key_id" pedantigo:"required,max_digits=32"`
}

Complete Example

Here's a comprehensive example showing multiple numeric constraints working together:

package main

import (
"fmt"
"github.com/smrutai/pedantigo"
)

type ECommerceProduct struct {
// Product ID: positive integer, at most 10 digits
ID int64 `json:"id" pedantigo:"required,positive,max_digits=10"`

// Product name: required, 3-100 characters
Name string `json:"name" pedantigo:"required,min=3,max=100"`

// Price in USD: required, at least 0.01, exactly 2 decimal places
Price float64 `json:"price" pedantigo:"required,min=0.01,decimal_places=2"`

// Cost basis: optional, for internal tracking
CostBasis float64 `json:"cost_basis,omitempty" pedantigo:"min=0,decimal_places=2"`

// Stock quantity: non-negative, less than 1 million
StockQuantity int `json:"stock_quantity" pedantigo:"required,min=0,max=999999"`

// Rating: 0-5 stars, one decimal place
Rating float64 `json:"rating,omitempty" pedantigo:"min=0,max=5,decimal_places=1"`

// Review count: non-negative
ReviewCount int `json:"review_count,omitempty" pedantigo:"min=0"`

// Discount percentage: 0-100, whole numbers only
DiscountPercent int `json:"discount_percent,omitempty" pedantigo:"min=0,max=100"`

// Weight in kilograms: positive, 4 decimal places
WeightKg float64 `json:"weight_kg,omitempty" pedantigo:"positive,decimal_places=4"`

// Dimensions in centimeters: all positive
WidthCm float64 `json:"width_cm,omitempty" pedantigo:"positive,decimal_places=1"`
HeightCm float64 `json:"height_cm,omitempty" pedantigo:"positive,decimal_places=1"`
DepthCm float64 `json:"depth_cm,omitempty" pedantigo:"positive,decimal_places=1"`

// Warranty period in months: 0 to 36, multiple of 3
WarrantyMonths int `json:"warranty_months,omitempty" pedantigo:"min=0,max=36,multiple_of=3"`
}

func main() {
// Valid product
productJSON := []byte(`{
"id": 123456789,
"name": "Professional Laptop Stand",
"price": 49.99,
"cost_basis": 20.00,
"stock_quantity": 150,
"rating": 4.5,
"review_count": 237,
"discount_percent": 10,
"weight_kg": 2.5000,
"width_cm": 45.5,
"height_cm": 12.0,
"depth_cm": 20.5,
"warranty_months": 24
}`)

product, err := pedantigo.Unmarshal[ECommerceProduct](productJSON)
if err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}

fmt.Printf("Valid product: %+v\n", product)

// Invalid product - multiple constraint violations
invalidJSON := []byte(`{
"id": 0,
"name": "Laptop Stand",
"price": 49.999,
"stock_quantity": 1000000,
"rating": 5.5,
"review_count": -10,
"discount_percent": 150,
"weight_kg": -2.5,
"width_cm": 45.123,
"warranty_months": 25
}`)

_, err = pedantigo.Unmarshal[ECommerceProduct](invalidJSON)
if err != nil {
fmt.Printf("Validation errors:\n%v\n", err)
// Output will show all numeric constraint violations:
// - id: must be greater than 0
// - price: can have at most 2 decimal places
// - stock_quantity: must be at most 999999
// - rating: must be at most 5
// - review_count: must be at least 0
// - discount_percent: must be at most 100
// - weight_kg: must be greater than 0
// - width_cm: can have at most 1 decimal place
// - warranty_months: must be a multiple of 3
}
}

Validation Behavior Notes

  • Zero values: Most numeric constraints skip validation for zero. Use required to enforce non-zero values, or positive/negative for sign constraints.
  • Type safety: Constraints work with all numeric types (signed/unsigned integers, floating-point numbers).
  • Precision: Floating-point comparisons use standard Go arithmetic; be cautious with decimal_places and extremely small values due to floating-point precision limits.
  • Nil values: Nil pointers are skipped in validation; use required to enforce non-nil.
  • Infinity and NaN: Only float32 and float64 can represent infinity or NaN. Use disallow_inf_nan to reject these values.

Quick Reference Table

ConstraintExampleDescriptionType Support
min=Nmin=0Minimum value (inclusive)All numeric
max=Nmax=100Maximum value (inclusive)All numeric
gt=Ngt=0Greater than (exclusive)All numeric
gte=Ngte=1Greater than or equal (inclusive)All numeric
lt=Nlt=100Less than (exclusive)All numeric
lte=Nlte=99Less than or equal (inclusive)All numeric
positivepositiveMust be > 0All numeric
negativenegativeMust be < 0All numeric
multiple_of=Nmultiple_of=5Must be divisible by NAll numeric
max_digits=Nmax_digits=8Maximum total digitsAll numeric
decimal_places=Ndecimal_places=2Maximum decimal placesfloat32, float64
disallow_inf_nandisallow_inf_nanReject infinity and NaNfloat32, float64

Comparison with Sign Constraints

ConstraintEquivalentAllows ZeroExample Use Case
positivegt=0NoAccount balance must be positive
gt=0positiveNoSame as positive
gte=0N/AYesQuantity can be zero or positive
negativelt=0NoTemperature below freezing
lt=0negativeNoSame as negative
lte=0N/AYesTemperature can be zero or negative

Real-World Validation Examples

E-commerce:

Price float64 `json:"price" pedantigo:"required,min=0.01,decimal_places=2"`
Quantity int `json:"quantity" pedantigo:"required,min=1,max=1000"`
DiscountPercent int `json:"discount" pedantigo:"min=0,max=100"`

Banking:

Balance float64 `json:"balance" pedantigo:"required,decimal_places=2,max_digits=15"`
WithdrawalAmount float64 `json:"amount" pedantigo:"required,positive,decimal_places=2"`
InterestRate float64 `json:"rate" pedantigo:"required,min=0,decimal_places=4"`

Scientific/Measurements:

Temperature float64 `json:"temp_celsius" pedantigo:"disallow_inf_nan"`
PressurePa float64 `json:"pressure" pedantigo:"required,positive"`
PH float64 `json:"ph" pedantigo:"required,min=0,max=14,decimal_places=2"`

Rating Systems:

Stars float64 `json:"stars" pedantigo:"min=0,max=5,multiple_of=0.5"`
Percentage int `json:"percentage" pedantigo:"required,min=0,max=100"`