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 modifier | Behavior |
|---|---|
.required() | Schema declaration: isRequired: true, isNullable: false |
.optional() | Schema declaration: isRequired: false, isNullable: true |
notNull | validateFieldValue() rejects null, undefined, and '' |
requiredIf | Rejects 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
| Rule | Applies to | Behavior |
|---|---|---|
minLength | TEXT, ARRAY | Minimum characters or entries |
maxLength | TEXT, ARRAY | Maximum characters or entries |
regex | String values | Tests a RegExp or regex source string |
Numeric constraints
| Rule | Applies to | Behavior |
|---|---|---|
greaterThan | Numeric values | Strict lower bound (>) |
lessThan | Numeric values | Strict upper bound (<) |
positive | NUMBER, NUMERIC | Rejects values below zero; zero passes in 0.9.50 |
isDecimal | NUMBER, NUMERIC | Requires a non-zero fractional component |
Numeric transforms
| Rule | Applies to | Behavior |
|---|---|---|
round | NUMBER, NUMERIC | Rounds to the configured decimal places |
floor | NUMBER, NUMERIC | Applies 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
| Rule | Behavior |
|---|---|
lessThanToday | Date must be strictly before local start-of-today |
greaterThanToday | Date 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
TEXTorARRAY, - negative lengths or
minLength > maxLength, greaterThan >= lessThan,- numeric math rules on non-numeric fields,
- a negative or fractional
round, floortogether withround,floororroundtogether withisDecimal,- both
lessThanTodayandgreaterThanToday.
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.