Skip to content

Union

Use union validation when one input value can match different validator types.

union

union validates one raw value against multiple validators and succeeds when at least one validator passes.

Internally, each validator is executed with validate(raw: Any?).

On success, union returns a tuple of optional values:

  • each tuple position corresponds to the validator at the same position in arguments
  • position is non-nil when that validator passed
  • position is nil when that validator failed

Important: more than one position can be non-nil if multiple validators accept the same input.

If no validators pass, union returns .failure with merged errors from all validators.

Parameters

  • value: Any - raw value to validate
  • rules: repeat each Rule - variadic validators conforming to FormCraftValidationTypeRules

Signature

swift
func union<each Rule: FormCraftValidationTypeRules>(
  _ value: Any,
  _ rules: repeat each Rule
) async -> FormCraftValidationResponse<(repeat ((each Rule).Value)?)>

For two rules (string, integer), success type is inferred as:

swift
FormCraftValidationResponse<(String?, Int?)>

Example: first rule passes

swift
let result = await FormCraftValidationRules().union(
  "hello@example.com",
  FormCraftValidationRules().string().email(),
  FormCraftValidationRules().integer().gt(num: 0)
)

switch result {
case .success(let (email, intValue)):
  if let email {
    print("Email:", email)
  }

  // `intValue` is `Int?` and will be `nil` here.
  if let intValue {
    print("Int:", intValue)
  }
case .failure(let errors):
  print(errors.messages)
}

Example: second rule passes

swift
let result = await FormCraftValidationRules().union(
  42,
  FormCraftValidationRules().string().notEmpty(),
  FormCraftValidationRules().integer().positive()
)

switch result {
case .success(let (stringValue, intValue)):
  // `stringValue` is `String?` and will be `nil` here.
  if let stringValue {
    print("String:", stringValue)
  }

  if let intValue {
    print("Int:", intValue) // 42
  }
case .failure(let errors):
  print(errors.messages)
}

Example: multiple rules pass

swift
let result = await FormCraftValidationRules().union(
  "42",
  FormCraftValidationRules().string().notEmpty(),
  FormCraftValidationRules().string().regex(/^\d+$/)
)

switch result {
case .success(let (raw, digitsOnly)):
  // Both are non-nil because both validators passed.
  print(raw ?? "")
  print(digitsOnly ?? "")
case .failure(let errors):
  print(errors.messages)
}

Released under the MIT License.