module CancerRegistryReportingTestKit::FHIRResourceNavigation
def find_a_value_at(element, path, include_dar: false, &block)
def find_a_value_at(element, path, include_dar: false, &block) return nil if element.nil? elements = Array.wrap(element) if path.empty? unless include_dar elements = elements.reject do |el| el.respond_to?(:extension) && el.extension.any? { |ext| ext.url == DAR_EXTENSION_URL } end end return elements.find(&block) if block_given? return elements.first end path_segments = path.split(/(?<!hl7)\./) ## special case: .gsub(':odh-UsualIndustry', '') # accounts for path traversal for Usual Work ODH profile segment = path_segments.shift.delete_suffix('[x]').gsub(/^class$/, 'local_class').gsub(/^method$/, 'local_method').gsub( '[x]:', ':').gsub(':odh-UsualIndustry', '').to_sym no_elements_present = elements.none? do |element| child = get_next_value(element, segment) child.present? || child == false end return nil if no_elements_present remaining_path = path_segments.join('.') elements.each do |element| child = get_next_value(element, segment) element_found = if block_given? find_a_value_at(child, remaining_path, include_dar: include_dar, &block) else find_a_value_at(child, remaining_path, include_dar: include_dar) end return element_found if element_found.present? || element_found == false end nil end
def find_slice_via_discriminator(element, property)
def find_slice_via_discriminator(element, property) element_name = property.to_s.split(':')[0].gsub(/^class$/, 'local_class').gsub(/^method$/, 'local_method') slice_name = property.to_s.split(':')[1].gsub(/^class$/, 'local_class').gsub(/^method$/, 'local_method') if metadata.present? slice_by_name = metadata.must_supports[:slices].find { |slice| slice[:slice_name] == slice_name } discriminator = slice_by_name[:discriminator] slices = Array.wrap(element.send(element_name)) slices.find do |slice| case discriminator[:type] when 'patternCodeableConcept' slice_value = discriminator[:path].present? ? slice.send(discriminator[:path].to_s)&.coding : slice.coding slice_value&.any? do |coding| coding.code == discriminator[:code] && coding.system == discriminator[:system] end when 'patternCoding' slice_value = discriminator[:path].present? ? slice.send(discriminator[:path]) : slice slice_value&.code == discriminator[:code] && slice_value&.system == discriminator[:system] when 'patternIdentifier' slice.identifier.system == discriminator[:system] when 'value' values = discriminator[:values].map { |value| value.merge(path: value[:path].split('.')) } verify_slice_by_values(slice, values) when 'type' case discriminator[:code] when 'Date' begin Date.parse(slice) rescue ArgumentError false end when 'DateTime' begin DateTime.parse(slice) rescue ArgumentError false end when 'String' slice.is_a? String else if slice.is_a? FHIR::Bundle::Entry slice.resource.is_a? FHIR.const_get(discriminator[:code]) else slice.is_a? FHIR.const_get(discriminator[:code]) end end when 'requiredBinding' discriminator[:path].present? ? slice.send(discriminator[:path].to_s).coding : slice.coding slice_value { |coding| discriminator[:values].include?(coding.code) } end end else # TODO: Error handling for if this file doesn't have access to metadata for some reason (begin/rescue with StandardError?) end end
def get_next_value(element, property)
def get_next_value(element, property) extension_url = property[/(?<=where\(url=').*(?='\))/] if extension_url.present? element.url == extension_url ? element : nil elsif property.to_s.include?(':') && !property.to_s.include?('url') find_slice_via_discriminator(element, property) else value = element.send(property) primitive_value = get_primitive_type_value(element, property, value) primitive_value.present? ? primitive_value : value end rescue NoMethodError nil end
def get_primitive_type_value(element, property, value)
def get_primitive_type_value(element, property, value) source_value = element.source_hash["_#{property}"] return nil unless source_value.present? primitive_value = CancerRegistryReportingTestKit::PrimitiveType.new(source_value) primitive_value.value = value primitive_value end
def resolve_path(elements, path)
def resolve_path(elements, path) elements = Array.wrap(elements) return elements if path.blank? paths = path.split(/(?<!hl7)\./) segment = paths.first remaining_path = paths.drop(1).join('.') elements.flat_map do |element| child = get_next_value(element, segment) resolve_path(child, remaining_path) end.compact end
def verify_slice_by_values(element, value_definitions)
def verify_slice_by_values(element, value_definitions) path_prefixes = value_definitions.map { |value_definition| value_definition[:path].first }.uniq path_prefixes.all? do |path_prefix| value_definitions_for_path = value_definitions .select { |value_definition| value_definition[:path].first == path_prefix } .each { |value_definition| value_definition[:path].shift } find_a_value_at(element, path_prefix) do |el_found| child_element_value_definitions, current_element_value_definitions = value_definitions_for_path.partition { |value_definition| value_definition[:path].present? } current_element_values_match = current_element_value_definitions .all? { |value_definition| value_definition[:value].to_s == el_found.to_s } child_element_values_match = if child_element_value_definitions.present? verify_slice_by_values(el_found, child_element_value_definitions) else true end current_element_values_match && child_element_values_match end end end