Class: USCoreTestKit::Generator::MustSupportMetadataExtractor
- Inherits:
-
Object
- Object
- USCoreTestKit::Generator::MustSupportMetadataExtractor
- Defined in:
- lib/us_core_test_kit/generator/must_support_metadata_extractor.rb
Instance Attribute Summary collapse
-
#ig_resources ⇒ Object
Returns the value of attribute ig_resources.
-
#profile ⇒ Object
Returns the value of attribute profile.
-
#profile_elements ⇒ Object
Returns the value of attribute profile_elements.
-
#resource ⇒ Object
Returns the value of attribute resource.
Instance Method Summary collapse
- #all_must_support_elements ⇒ Object
- #discriminators(slice) ⇒ Object
- #element_part_of_slice_discrimination?(element) ⇒ Boolean
- #get_type_must_support_metadata(current_metadata, current_element) ⇒ Object
- #handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata) ⇒ Object
- #handle_fixed_values(metadata, element) ⇒ Object
-
#handle_special_cases ⇒ Object
SPECIAL CASE ####.
- #handle_type_must_support_target_profiles(type, metadata) ⇒ Object
-
#initialize(profile_elements, profile, resource, ig_resources) ⇒ MustSupportMetadataExtractor
constructor
A new instance of MustSupportMetadataExtractor.
- #is_blood_pressure? ⇒ Boolean
- #is_uscdi_requirement_element?(element) ⇒ Boolean
- #is_vital_sign? ⇒ Boolean
- #must_support_elements ⇒ Object
- #must_support_extension_elements ⇒ Object
- #must_support_extensions ⇒ Object
- #must_support_pattern_slice_elements ⇒ Object
- #must_support_slice_elements ⇒ Object
- #must_support_slices ⇒ Object
- #must_support_type_slice_elements ⇒ Object
- #must_support_value_slice_elements ⇒ Object
- #must_supports ⇒ Object
- #pattern_slices ⇒ Object
- #plain_must_support_elements ⇒ Object
-
#remove_blood_pressure_value_data_absent_reason ⇒ Object
Exclude Observation.value[x] from observation-bp.
-
#remove_observation_data_absent_reason ⇒ Object
ONC and US Core 4.0.0 both clarified that health IT developers that always provide HL7 FHIR “observation” values are not required to demonstrate Health IT Module support for “dataAbsentReason” elements.
-
#remove_vital_sign_component ⇒ Object
Exclude Observation.component from vital sign profiles except observation-bp and observation-pulse-ox.
- #save_type_code?(type) ⇒ Boolean
- #sliced_element(slice) ⇒ Object
- #type_must_support_extension?(extensions) ⇒ Boolean
- #type_slices ⇒ Object
- #value_slices ⇒ Object
Constructor Details
#initialize(profile_elements, profile, resource, ig_resources) ⇒ MustSupportMetadataExtractor
Returns a new instance of MustSupportMetadataExtractor.
13 14 15 16 17 18 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 13 def initialize(profile_elements, profile, resource, ig_resources) self.profile_elements = profile_elements self.profile = profile self.resource = resource self.ig_resources = ig_resources end |
Instance Attribute Details
#ig_resources ⇒ Object
Returns the value of attribute ig_resources.
11 12 13 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 11 def ig_resources @ig_resources end |
#profile ⇒ Object
Returns the value of attribute profile.
11 12 13 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 11 def profile @profile end |
#profile_elements ⇒ Object
Returns the value of attribute profile_elements.
11 12 13 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 11 def profile_elements @profile_elements end |
#resource ⇒ Object
Returns the value of attribute resource.
11 12 13 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 11 def resource @resource end |
Instance Method Details
#all_must_support_elements ⇒ Object
39 40 41 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 39 def all_must_support_elements profile_elements.select { |element| (element.mustSupport || is_uscdi_requirement_element?(element))} end |
#discriminators(slice) ⇒ Object
69 70 71 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 69 def discriminators(slice) slice.slicing.discriminator end |
#element_part_of_slice_discrimination?(element) ⇒ Boolean
219 220 221 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 219 def element_part_of_slice_discrimination?(element) must_support_slice_elements.any? { |ms_slice| element.id.include?(ms_slice.id) } end |
#get_type_must_support_metadata(current_metadata, current_element) ⇒ Object
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 249 def (, current_element) current_element.type.map do |type| if type_must_support_extension?(type.extension) = { path: "#{[:path].delete_suffix('[x]')}#{type.code.upcase_first}", original_path: [:path] } [:types] = [type.code] if save_type_code?(type) handle_type_must_support_target_profiles(type, ) if type.code == 'Reference' end end.compact end |
#handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata) ⇒ Object
288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 288 def handle_choice_type_in_sliced_element(, ) = .find do || [:original_path].present? && [:path].include?( [:original_path] ) end if .present? [:original_path] = [:path] [:path] = [:path].sub([:original_path], [:path]) end end |
#handle_fixed_values(metadata, element) ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 224 def handle_fixed_values(, element) if element.fixedUri.present? [:fixed_value] = element.fixedUri elsif element.patternCodeableConcept.present? && !element_part_of_slice_discrimination?(element) [:fixed_value] = element.patternCodeableConcept.coding.first.code [:path] += '.coding.code' elsif element.fixedCode.present? [:fixed_value] = element.fixedCode elsif element.patternIdentifier.present? && !element_part_of_slice_discrimination?(element) [:fixed_value] = element.patternIdentifier.system [:path] += '.system' end end |
#handle_special_cases ⇒ Object
SPECIAL CASE ####
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 335 def handle_special_cases remove_vital_sign_component remove_blood_pressure_value_data_absent_reason remove_observation_data_absent_reason case profile.version when '3.1.1' MustSupportMetadataExtractorUsCore3.new(profile, @must_supports).handle_special_cases when '4.0.0' MustSupportMetadataExtractorUsCore4.new(profile, @must_supports).handle_special_cases when '5.0.1' MustSupportMetadataExtractorUsCore5.new(profile, @must_supports).handle_special_cases when '6.1.0' MustSupportMetadataExtractorUsCore6.new(profile, @must_supports).handle_special_cases when '7.0.0' MustSupportMetadataExtractorUsCore7.new(profile, @must_supports).handle_special_cases end end |
#handle_type_must_support_target_profiles(type, metadata) ⇒ Object
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 265 def handle_type_must_support_target_profiles(type, ) # US Core 3.1.1 profiles do not have US Core target profiles. # Vital Sign proifles from FHIR R4 (version 4.0.1) do not have US Core target profiles either. return if ['3.1.1', '4.0.1'].include?(profile.version) target_profiles = [] if type.targetProfile&.length == 1 target_profiles << type.targetProfile.first else type.source_hash['_targetProfile']&.each_with_index do |hash, index| if hash.present? element = FHIR::Element.new(hash) target_profiles << type.targetProfile[index] if type_must_support_extension?(element.extension) end end end # remove target_profile for FHIR Base resource type. target_profiles.delete_if { |reference| reference.start_with?('http://hl7.org/fhir/StructureDefinition')} [:target_profiles] = target_profiles if target_profiles.present? end |
#is_blood_pressure? ⇒ Boolean
361 362 363 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 361 def is_blood_pressure? ['bp', 'us-core-blood-pressure', 'us-core-average-blood-pressure'].include?(profile.id) end |
#is_uscdi_requirement_element?(element) ⇒ Boolean
32 33 34 35 36 37 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 32 def is_uscdi_requirement_element?(element) element.extension.any? do |extension| extension.url == 'http://hl7.org/fhir/us/core/StructureDefinition/uscdi-requirement' && extension.valueBoolean end && !element.mustSupport end |
#is_vital_sign? ⇒ Boolean
354 355 356 357 358 359 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 354 def is_vital_sign? [ 'http://hl7.org/fhir/StructureDefinition/vitalsigns', 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-vital-signs' ].include?(profile.baseDefinition) end |
#must_support_elements ⇒ Object
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 300 def must_support_elements plain_must_support_elements.each_with_object([]) do |current_element, | { path: current_element.id.gsub("#{resource}.", '') }.tap do || if is_uscdi_requirement_element?(current_element) [:uscdi_only] = true end = (, current_element) if .any? .concat() else handle_choice_type_in_sliced_element(, ) supported_types = current_element.type.select { |type| save_type_code?(type) }.map { |type| type.code } [:types] = supported_types if supported_types.present? handle_type_must_support_target_profiles(current_element.type.first, ) if current_element.type.first&.code == 'Reference' handle_fixed_values(, current_element) .delete_if do || [:path] == [:path] && [:fixed_value].blank? end << end end end.uniq end |
#must_support_extension_elements ⇒ Object
43 44 45 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 43 def must_support_extension_elements all_must_support_elements.select { |element| element.path.end_with? 'extension' } end |
#must_support_extensions ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 47 def must_support_extensions must_support_extension_elements.map do |element| { id: element.id, path: element.path.gsub("#{resource}.", ''), url: element.type.first.profile.first }.tap do || if is_uscdi_requirement_element?(element) [:uscdi_only] = true end end end end |
#must_support_pattern_slice_elements ⇒ Object
73 74 75 76 77 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 73 def must_support_pattern_slice_elements must_support_slice_elements.select do |element| discriminators(sliced_element(element)).first.type == 'pattern' end end |
#must_support_slice_elements ⇒ Object
61 62 63 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 61 def must_support_slice_elements all_must_support_elements.select { |element| !element.path.end_with?('extension') && element.sliceName.present? } end |
#must_support_slices ⇒ Object
211 212 213 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 211 def must_support_slices pattern_slices + type_slices + value_slices end |
#must_support_type_slice_elements ⇒ Object
140 141 142 143 144 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 140 def must_support_type_slice_elements must_support_slice_elements.select do |element| discriminators(sliced_element(element)).first.type == 'type' end end |
#must_support_value_slice_elements ⇒ Object
176 177 178 179 180 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 176 def must_support_value_slice_elements must_support_slice_elements.select do |element| discriminators(sliced_element(element)).first.type == 'value' end end |
#must_supports ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 20 def must_supports @must_supports = { extensions: must_support_extensions, slices: must_support_slices, elements: must_support_elements } handle_special_cases @must_supports end |
#pattern_slices ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 79 def pattern_slices must_support_pattern_slice_elements.map do |current_element| { slice_id: current_element.id, slice_name: current_element.sliceName, path: current_element.path.gsub("#{resource}.", '') }.tap do || discriminator = discriminators(sliced_element(current_element)).first discriminator_path = discriminator.path discriminator_path = '' if discriminator_path == '$this' pattern_element = if discriminator_path.present? profile_elements.find { |element| element.id == "#{current_element.id}.#{discriminator_path}" } else current_element end [:discriminator] = if pattern_element.patternCodeableConcept.present? { type: 'patternCodeableConcept', path: discriminator_path, code: pattern_element.patternCodeableConcept.coding.first.code, system: pattern_element.patternCodeableConcept.coding.first.system } elsif pattern_element.patternCoding.present? { type: 'patternCoding', path: discriminator_path, code: pattern_element.patternCoding.code, system: pattern_element.patternCoding.system } elsif pattern_element.patternIdentifier.present? { type: 'patternIdentifier', path: discriminator_path, system: pattern_element.patternIdentifier.system } elsif pattern_element.binding&.strength == 'required' && pattern_element.binding&.valueSet.present? value_extractor = ValueExactor.new(ig_resources, resource, profile_elements) values = value_extractor.codings_from_value_set_binding(pattern_element).presence || value_extractor.([[:path]]).presence || [] { type: 'requiredBinding', path: discriminator_path, values: values } else raise StandardError, 'Unsupported discriminator pattern type' end if is_uscdi_requirement_element?(current_element) [:uscdi_only] = true end end end end |
#plain_must_support_elements ⇒ Object
215 216 217 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 215 def plain_must_support_elements plain_must_supports = all_must_support_elements - must_support_extension_elements - must_support_slice_elements end |
#remove_blood_pressure_value_data_absent_reason ⇒ Object
Exclude Observation.value[x] from observation-bp
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 377 def remove_blood_pressure_value_data_absent_reason return unless is_blood_pressure? pattern = /component(:[^.]+)?\.dataAbsentReason/ @must_supports[:elements].delete_if do |element| element[:path].start_with?('value[x]') || element[:original_path]&.start_with?('value[x]') || element[:path] == ('dataAbsentReason') || ( pattern.match?(element[:path]) && ['3.1.1', '4.0.0'].include?(ig_resources.ig.version) ) end @must_supports[:slices].delete_if do |slice| slice[:path].start_with?('value[x]') end end |
#remove_observation_data_absent_reason ⇒ Object
ONC and US Core 4.0.0 both clarified that health IT developers that always provide HL7 FHIR “observation” values are not required to demonstrate Health IT Module support for “dataAbsentReason” elements. Remove MS check for dataAbsentReason and component.dataAbsentReason from vital sign profiles and observation lab profile Smoking status profile does not have MS on dataAbsentReason. It is safe to use profile.type == ‘Observation’ Since US Core 5.0.1, Blood Pressure profile restores component.dataAbsentReason as MustSupport.
401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 401 def remove_observation_data_absent_reason return if is_blood_pressure? pattern = /(component(:[^.]+)?\.)?dataAbsentReason/ if profile.type == 'Observation' @must_supports[:elements].delete_if do |element| pattern.match?(element[:path]) end end end |
#remove_vital_sign_component ⇒ Object
Exclude Observation.component from vital sign profiles except observation-bp and observation-pulse-ox
366 367 368 369 370 371 372 373 374 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 366 def remove_vital_sign_component return if is_blood_pressure? || profile.name == 'USCorePulseOximetryProfile' if is_vital_sign? @must_supports[:elements].delete_if do |element| element[:path].start_with?('component') end end end |
#save_type_code?(type) ⇒ Boolean
245 246 247 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 245 def save_type_code?(type) 'Reference' == type.code end |
#sliced_element(slice) ⇒ Object
65 66 67 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 65 def sliced_element(slice) profile_elements.find { |element| element.id == slice.path || element.id == slice.id.sub(":#{slice.sliceName}", '') } end |
#type_must_support_extension?(extensions) ⇒ Boolean
238 239 240 241 242 243 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 238 def type_must_support_extension?(extensions) extensions&.any? do |extension| extension.url == 'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support' && extension.valueBoolean end end |
#type_slices ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 146 def type_slices must_support_type_slice_elements.map do |current_element| discriminator = discriminators(sliced_element(current_element)).first type_path = discriminator.path type_path = '' if type_path == '$this' type_element = if type_path.present? elements.find { |element| element.id == "#{current_element.id}.#{type_path}" } else current_element end type_code = type_element.type.first.code { slice_id: current_element.id, slice_name: current_element.sliceName, path: current_element.path.gsub("#{resource}.", ''), discriminator: { type: 'type', code: type_code.upcase_first } }.tap do || if is_uscdi_requirement_element?(current_element) [:uscdi_only] = true end end end end |
#value_slices ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/us_core_test_kit/generator/must_support_metadata_extractor.rb', line 182 def value_slices must_support_value_slice_elements.map do |current_element| { slice_id: current_element.id, slice_name: current_element.sliceName, path: current_element.path.gsub("#{resource}.", ''), discriminator: { type: 'value' } }.tap do || [:discriminator][:values] = discriminators(sliced_element(current_element)).map do |discriminator| fixed_element = profile_elements.find do |element| element.id.starts_with?(current_element.id) && element.path == "#{current_element.path}.#{discriminator.path}" end { path: discriminator.path, value: fixed_element.fixedUri || fixed_element.fixedCode } end if is_uscdi_requirement_element?(current_element) [:uscdi_only] = true end end end end |