Validation

Validation rules stay on the same field chain as its stored type:

const amount = bd
  .number()
  .required()
  .validate({
    greaterThan: 0,
    lessThan: 10000,
    positive: true,
    round: 2,
  })

Successive validation modifiers merge into one ValidationRules object:

const code = bd
  .text()
  .validate({ minLength: 6, maxLength: 12 })
  .regex(/^[A-Z][A-Z0-9_-]+$/)

For the distinction between rule definitions, current errors, and server validation, read Validation and Form State.

Presence rules

Rule or modifierBehavior
.required()Schema declaration: isRequired: true, isNullable: false
.optional()Schema declaration: isRequired: false, isNullable: true
notNullvalidateFieldValue() rejects null, undefined, and ''
requiredIfRejects an empty value when sibling context matches
const purchaseOrder = bd.text().requiredIf({
  fieldRef: 'paymentMethod',
  op: 'equals',
  values: ['invoice'],
})

requiredIf accepts equals or notEquals.

Length and pattern rules

RuleApplies toBehavior
minLengthTEXT, ARRAYMinimum characters or entries
maxLengthTEXT, ARRAYMaximum characters or entries
regexString valuesTests a RegExp or regex source string

Numeric constraints

RuleApplies toBehavior
greaterThanNumeric valuesStrict lower bound (>)
lessThanNumeric valuesStrict upper bound (<)
positiveNUMBER, NUMERICRejects values below zero; zero passes in 0.9.50
isDecimalNUMBER, NUMERICRequires a non-zero fractional component

Numeric transforms

RuleApplies toBehavior
roundNUMBER, NUMERICRounds to the configured decimal places
floorNUMBER, NUMERICApplies Math.floor()

Transforms return their normalized number through result.value:

const result = validateFieldValue(12.345, { round: 2 })

if (result.valid) {
  save(result.value) // 12.35
}

Date rules

RuleBehavior
lessThanTodayDate must be strictly before local start-of-today
greaterThanTodayDate must be strictly after local start-of-today
specificDateValue: 'today()'Parsed timestamp must equal local start-of-today

SpecialDateValue also accepts a string or Date, but the 0.9.50 runtime does not compare those forms. Use the three enforced forms above when relying on validateFieldValue().

Definition-time checks

createSchema() rejects invalid combinations before an artifact is produced:

  • length rules on a type other than TEXT or ARRAY,
  • negative lengths or minLength > maxLength,
  • greaterThan >= lessThan,
  • numeric math rules on non-numeric fields,
  • a negative or fractional round,
  • floor together with round,
  • floor or round together with isDecimal,
  • both lessThanToday and greaterThanToday.

These failures describe an invalid developer definition. They are not visitor-facing field errors.

Validate one field

import { validateFieldValue } from '@businessdash/sdk'

const result = validateFieldValue(
  undefined,
  {
    requiredIf: {
      fieldRef: 'paymentMethod',
      op: 'equals',
      values: ['invoice'],
    },
  },
  { paymentMethod: 'invoice' },
)

The return type is:

{
  valid: boolean
  value: unknown
  error?: string
}

An empty value passes unless notNull or a matching requiredIf requires it.

Measurement validation

validateAndResolveMeasurement() checks the number, decimal policy, and fixed unit membership for a measurement definition:

const result = validateAndResolveMeasurement(
  { value: 125, unit: 'cm' },
  {
    category: 'length',
    unitPicker: 'fixed',
    default_unit: 'cm',
    resolve_to_your_unit: 'cm',
    allow_decimals: true,
  },
)

SQL check metadata

const balance = bd.number().check('balance >= 0')

.check() stores validation.checkExpression. validateFieldValue() does not execute SQL or evaluate that expression.

Published-form validation is separate

validateFormSubmission(schema, data) validates data against the dashboard-authored FormSchema returned by forms.schema(slug). It does not take a ValidationRules object or uiFormTree.

The Live server validates again during submission and remains authoritative.

Next: Form Elements.