Class: ONCCertificationG10TestKit::TerminologyBindingValidator

Inherits:
Object
  • Object
show all
Includes:
Inferno::Terminology::TerminologyValidation, USCoreTestKit::FHIRResourceNavigation
Defined in:
lib/onc_certification_g10_test_kit/terminology_binding_validator.rb

Constant Summary

Constants included from Inferno::Terminology::TerminologyValidation

Inferno::Terminology::TerminologyValidation::PREPROCESS_FUNCS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Inferno::Terminology::TerminologyValidation

#validate_code, #validators_repo

Constructor Details

#initialize(resource, binding_definition) ⇒ TerminologyBindingValidator

Returns a new instance of TerminologyBindingValidator.



15
16
17
18
19
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 15

def initialize(resource, binding_definition)
  @resource = resource
  @binding_definition = binding_definition
  @validation_messages = []
end

Instance Attribute Details

#binding_definitionObject (readonly)

Returns the value of attribute binding_definition.



13
14
15
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 13

def binding_definition
  @binding_definition
end

#resourceObject (readonly)

Returns the value of attribute resource.



13
14
15
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 13

def resource
  @resource
end

#validation_messagesObject (readonly)

Returns the value of attribute validation_messages.



13
14
15
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 13

def validation_messages
  @validation_messages
end

Class Method Details

.validateObject



9
10
11
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 9

def self.validate(...)
  new(...).validate
end

Instance Method Details

#add_error(element) ⇒ Object



70
71
72
73
74
75
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 70

def add_error(element)
  validation_messages << {
    type: 'error',
    message: invalid_binding_message(element)
  }
end

#add_warning(message) ⇒ Object



77
78
79
80
81
82
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 77

def add_warning(message)
  validation_messages << {
    type: 'warning',
    message:
  }
end

#element_code(element) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 84

def element_code(element)
  case element
  when FHIR::CodeableConcept
    element&.coding&.map do |coding|
      "`#{coding.system}|#{coding.code}`"
    end&.join(' or ')
  when FHIR::Coding, FHIR::Quantity
    "`#{element.system}|#{element.code}`"
  else
    "`#{element}`"
  end
end

#element_with_invalid_bindingObject



63
64
65
66
67
68
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 63

def element_with_invalid_binding
  @element_with_invalid_binding ||=
    find_a_value_at(path_source, binding_definition[:path]) do |element|
      invalid_binding? element
    end
end

#invalid_binding?(element) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
113
114
115
116
117
118
119
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 110

def invalid_binding?(element)
  case binding_definition[:type]
  when 'CodeableConcept'
    invalid_codeable_concept? element
  when 'Quantity', 'Coding'
    invalid_coding? element
  when 'code'
    invalid_code? element
  end
end

#invalid_binding_message(element) ⇒ Object



101
102
103
104
105
106
107
108
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 101

def invalid_binding_message(element)
  system = binding_definition[:system].presence || 'the declared CodeSystem'

  %(
    #{resource_type}/#{resource.id} at #{resource_type}.#{binding_definition[:path]}
    with code #{element_code(element)} is not in #{system}.
  )
end

#invalid_code?(element) ⇒ Boolean

Returns:

  • (Boolean)


162
163
164
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 162

def invalid_code?(element)
  !validate_code(value_set_url: binding_definition[:system], code: element)
end

#invalid_codeable_concept?(element) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 121

def invalid_codeable_concept?(element)
  return unless element.is_a? FHIR::CodeableConcept

  if binding_definition[:system].present?
    element.coding.none? do |coding|
      validate_code(
        value_set_url: binding_definition[:system],
        code: coding.code,
        system: coding.system
      )
    rescue Inferno::ProhibitedSystemException => e
      add_warning(e.message)
      false
    end
  # If we're validating a codesystem (AKA if there's no 'system' URL)
  # We want all of the codes to be in their respective systems
  else
    el.coding.any? do |coding|
      !validate_code(
        value_set_url: nil,
        code: coding.code,
        system: coding.system
      )
    rescue Inferno::ProhibitedSystemException => e
      add_warning(e.message)
      false
    end
  end
end

#invalid_coding?(element) ⇒ Boolean

Returns:

  • (Boolean)


151
152
153
154
155
156
157
158
159
160
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 151

def invalid_coding?(element)
  !validate_code(
    value_set_url: binding_definition[:system],
    code: element.code,
    system: element.system
  )
rescue Inferno::ProhibitedSystemException => e
  add_warning(e.message)
  false
end

#path_sourceObject



53
54
55
56
57
58
59
60
61
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 53

def path_source
  return resource if binding_definition[:extensions].blank?

  binding_definition[:extensions].reduce(Array.wrap(resource)) do |elements, extension_url|
    elements.flat_map do |element|
      element.extension.select { |extension| extension.url == extension_url }
    end
  end
end

#resource_typeObject



97
98
99
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 97

def resource_type
  resource.resourceType
end

#validateObject



21
22
23
24
25
26
27
28
29
30
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 21

def validate
  # Handle special case due to required binding on a slice
  if binding_definition[:required_binding_slice]
    validate_required_binding_slice
  else
    add_error(element_with_invalid_binding) if element_with_invalid_binding.present? # rubocop:disable Style/IfInsideElse
  end

  validation_messages
end

#validate_required_binding_sliceObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/onc_certification_g10_test_kit/terminology_binding_validator.rb', line 32

def validate_required_binding_slice
  valid_binding =
    find_a_value_at(path_source, binding_definition[:path]) do |element|
      !invalid_binding?(element)
    end

  return if valid_binding.present?

  system = binding_definition[:system].presence || 'the declared Value Set'

  error_message = %(
    #{resource_type}/#{resource.id} at #{resource_type}.#{binding_definition[:path]}
    does not contain a valid code from #{system}.
  )

  validation_messages << {
    type: 'error',
    message: error_message
  }
end