HL7v2.Validation.ProfileRules (HL7v2 v3.10.1)

Copy Markdown View Source

Evaluates a HL7v2.Profile against a typed message and returns validation errors. Called from HL7v2.Validation.validate/2 when a :profile option is provided.

Profile errors include :rule (which rule type fired) and :profile (profile name) fields in addition to the standard :level/:location/:field/:message shape used by the rest of the validation stack.

Rule Evaluation Order

For each profile, the following checks run in order and all errors from all checks are collected (short-circuiting is intentionally avoided so integrators see a complete diagnostic in one pass):

  1. require_segment — every segment in profile.required_segments must appear
  2. forbid_segment — no segment in profile.forbidden_segments may appear
  3. require_field — every {seg_id, field_seq} must be populated when its segment is present; missing segment is also an error
  4. forbid_field — every {seg_id, field_seq} in profile.forbidden_fields must be blank or absent
  5. require_value — a declarative equality or membership pin on a field (from Profile.require_value/5 or Profile.require_value_in/5)
  6. require_component — a declarative component/subcomponent pin on a composite field (from Profile.require_component/5)
  7. bind_table — a field's value must be in a specific HL7 table (from Profile.bind_table/4)
  8. require_cardinality — segment occurrence counts must fall within {min, max}
  9. value_constraint — custom predicate on a field value (only when field present)
  10. custom_rule — arbitrary function returning error maps

Custom rule errors are tagged with :rule (the rule name) and :profile (the profile name) if the rule did not set them. If a custom rule raises, a synthetic :custom_rule_exception error is emitted — exceptions are never silently swallowed.

Applicability

A profile is applied only when its :message_type tuple matches the typed message's code/event AND (when declared) its :version matches the version in MSH-12. A profile with nil :message_type matches any type; a profile with nil :version matches any version.

"Blank" semantics

Several rules (require_field, forbid_field, require_value, require_component) share a single blank?/1 helper that treats any of the following as blank:

  • nil
  • ""
  • []
  • a list whose elements are all themselves blank
  • a struct whose every field is blank (checked recursively)

The last clause means a composite field like %HL7v2.Type.CE{} with every subcomponent set to nil is considered blank — which is the right answer for "is PID-3 populated?" but may surprise callers who consider a CE with only an alternate_identifier to be "empty" or "populated" depending on their use case. If your rule needs stricter semantics, prefer require_value/5 with an accessor or require_component/5 targeting a specific subcomponent.

Summary

Functions

Evaluates a profile against a typed message.

Types

error()

@type error() :: %{
  level: :error | :warning,
  location: String.t(),
  field: atom() | nil,
  message: String.t(),
  rule: atom(),
  profile: String.t()
}

Functions

check(msg, profile)

@spec check(HL7v2.TypedMessage.t(), HL7v2.Profile.t()) :: [error()]

Evaluates a profile against a typed message.

Returns [] if the message satisfies all profile rules, or a list of error maps describing each violation.

If the profile declares a :message_type and it doesn't match the typed message's type, the profile is considered not applicable and [] is returned — it is the caller's responsibility to decide whether a non-matching profile is itself an error.