Class: DaVinciPASTestKit::PASMustSupportMetadataExtractor
- Inherits:
-
Inferno::DSL::MustSupportMetadataExtractor
- Object
- Inferno::DSL::MustSupportMetadataExtractor
- DaVinciPASTestKit::PASMustSupportMetadataExtractor
- Defined in:
- lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb
Overview
The MustSupportMetadataExtractor takes a StructureDefinition and parses it into a hash-based metadata that simplifies checking for MustSupport elements. MustSupport elements may be either plain elements, extensions, or slices. This logic was originally developed for the US Core Test Kit and has been migrated into Inferno core.
Instance Method Summary collapse
- #find_element_by_discriminator_path(current_element, discriminator_path) ⇒ Object
-
#save_pattern_slice(pattern_element, discriminator_path, metadata) ⇒ Object
Override save_pattern_slice to handle patternIdentifier slices that discriminate on identifier.type.coding (e.g. Organization.identifier:PI) rather than identifier.system.
-
#take_discriminator_step(current_element, path) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity.
-
#value_slices ⇒ Object
rubocop:enable Metrics/CyclomaticComplexity.
Instance Method Details
#find_element_by_discriminator_path(current_element, discriminator_path) ⇒ Object
31 32 33 34 35 36 37 38 39 40 |
# File 'lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb', line 31 def find_element_by_discriminator_path(current_element, discriminator_path) target_element = current_element remaining_path = discriminator_path while remaining_path.present? target_element, remaining_path = take_discriminator_step(target_element, remaining_path) end target_element end |
#save_pattern_slice(pattern_element, discriminator_path, metadata) ⇒ Object
Override save_pattern_slice to handle patternIdentifier slices that discriminate on identifier.type.coding (e.g. Organization.identifier:PI) rather than identifier.system. inferno_core only extracts .system from patternIdentifier, leaving it nil for type-coded slices, which causes find_pattern_identifier_slice to never match at runtime. When patternIdentifier.type.coding is present, emit a patternCodeableConcept discriminator on path 'type' instead, which inferno_core CAN navigate at runtime.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb', line 15 def save_pattern_slice(pattern_element, discriminator_path, ) pi_type = pattern_element.patternIdentifier&.type coding = pi_type&.coding&.first if coding runtime_path = (discriminator_path) path = runtime_path.present? ? "#{runtime_path}.type" : 'type' return { type: 'patternCodeableConcept', path: path, code: coding.code, system: coding.system } end super end |
#take_discriminator_step(current_element, path) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb', line 43 def take_discriminator_step(current_element, path) if path.start_with?('extension(') ext_url, remaining_path = path.delete_prefix("extension('").split("')", 2) next_element = profile_elements.find do |element| element.path == "#{current_element.path}.extension" && element.id.start_with?("#{current_element.id}.extension:") && element.type.any? { |type| type.code == 'Extension' && type.profile.any? { |p| p.start_with?(ext_url) } } end else step_path, remaining_path = path.split('.', 2) if remaining_path&.start_with?('ofType(') target_element = "#{step_path}[x]" target_type, remaining_path = remaining_path.delete_prefix('ofType(').split(')', 2) next_element = profile_elements.find do |element| element.id == "#{current_element.id}.#{target_element}" && element.type.any? { |type| type.code == target_type } end elsif step_path.include?(' as ') # Handle FHIR FHIRPath "value as boolean" cast syntax (equivalent to ofType()) base_step, cast_type = step_path.split(' as ', 2) target_element_path = "#{base_step.strip}[x]" next_element = profile_elements.find do |element| element.id == "#{current_element.id}.#{target_element_path}" && element.type.any? { |type| type.code == cast_type.strip } end else next_element = profile_elements.find { |element| element.id == "#{current_element.id}.#{step_path}" } || profile_elements.find { |element| element.id == "#{current_element.path}.#{step_path}" } end end [next_element, remaining_path&.delete_prefix('.')] end |
#value_slices ⇒ Object
rubocop:enable Metrics/CyclomaticComplexity
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 |
# File 'lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb', line 79 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}.", '') }.tap do || fixed_values = [] pattern_value = {} element_discriminators = discriminators(sliced_element(current_element)) element_discriminators.each do |discriminator| discriminator_path = discriminator_path(discriminator) pattern_element = find_element_by_discriminator_path(current_element, discriminator_path) # This is a workaround for a known version of a profile that has a bad discriminator: # the discriminator refers to a nested field within a CodeableConcept, # but the profile doesn't contain an element definition for it, so there's no way to # define a fixed value on the element to define the slice. # In this instance the element has a second (good) discriminator on the CodeableConcept field itself, # and in subsequent versions of the profile, the bad discriminator was removed. next if pattern_element.nil? && element_discriminators.length > 1 if !pattern_element.fixed.nil? fixed_values << { path: (discriminator_path), value: pattern_element.fixed } elsif pattern_value.present? raise StandardError, "Found more than one pattern slices for the same element #{pattern_element}." else pattern_value = save_pattern_slice(pattern_element, discriminator_path, ) end end if fixed_values.present? [:discriminator] = { type: 'value', values: fixed_values } elsif pattern_value.present? [:discriminator] = pattern_value end [:by_requirement_extension_only] = true if by_requirement_extension_only?(current_element) end end end |