Module: USCoreTestKit::ResourceSearchParamChecker

Includes:
FHIRResourceNavigation
Included in:
GranularScopeReadTest, GranularScopeSearchTest, SearchTest
Defined in:
lib/us_core_test_kit/resource_search_param_checker.rb

Constant Summary

Constants included from FHIRResourceNavigation

FHIRResourceNavigation::DAR_EXTENSION_URL, FHIRResourceNavigation::PRIMITIVE_DATA_TYPES

Instance Method Summary collapse

Methods included from FHIRResourceNavigation

#find_a_value_at, #find_slice_via_discriminator, #get_next_value, #get_primitive_type_value, #resolve_path, #verify_slice_by_values

Instance Method Details

#element_has_valid_value?(element, include_system) ⇒ Boolean

Returns:

  • (Boolean)


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/us_core_test_kit/resource_search_param_checker.rb', line 16

def element_has_valid_value?(element, include_system)
  case element
  when FHIR::Reference
    element.reference.present?
  when FHIR::CodeableConcept
    if include_system
      coding =
        find_a_value_at(element, 'coding') { |coding| coding.code.present? && coding.system.present? }
      coding.present?
    else
      find_a_value_at(element, 'coding.code').present?
    end
  when FHIR::Identifier
    include_system ? element.value.present? && element.system.present? : element.value.present?
  when FHIR::Coding
    include_system ? element.code.present? && element.system.present? : element.code.present?
  when FHIR::HumanName
    (element.family || element.given&.first || element.text).present?
  when FHIR::Address
    (element.text || element.city || element.state || element.postalCode || element.country).present?
  when FHIR::Element
    false
  else
    true
  end
end

#resource_matches_param?(resource, search_param_name, escaped_search_value, values_found = []) ⇒ Boolean

Returns:

  • (Boolean)


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
77
78
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
# File 'lib/us_core_test_kit/resource_search_param_checker.rb', line 43

def resource_matches_param?(resource, search_param_name, escaped_search_value, values_found = [])
  search_value = unescape_search_value(escaped_search_value)
  paths = search_param_paths(search_param_name)

  match_found = false

  paths.each do |path|
    type = .search_definitions[search_param_name.to_sym][:type]
    values_found =
      resolve_path(resource, path)
        .map do |value|
      if value.is_a? FHIR::Reference
        value.reference
      else
        value
      end
    end

    match_found =
      case type
      when 'Period', 'date', 'instant', 'dateTime'
        values_found.any? { |date| validate_date_search(search_value, date) }
      when 'HumanName'
        # When a string search parameter refers to the types HumanName and Address,
        # the search covers the elements of type string, and does not cover elements such as use and period
        # https://www.hl7.org/fhir/search.html#string
        search_value_downcase = search_value.downcase
        values_found.any? do |name|
          name&.text&.downcase&.start_with?(search_value_downcase) ||
            name&.family&.downcase&.start_with?(search_value_downcase) ||
            name&.given&.any? { |given| given.downcase.start_with?(search_value_downcase) } ||
            name&.prefix&.any? { |prefix| prefix.downcase.start_with?(search_value_downcase) } ||
            name&.suffix&.any? { |suffix| suffix.downcase.start_with?(search_value_downcase) }
        end
      when 'Address'
        search_value_downcase = search_value.downcase
        values_found.any? do |address|
          address&.text&.downcase&.start_with?(search_value_downcase) ||
            address&.city&.downcase&.start_with?(search_value_downcase) ||
            address&.state&.downcase&.start_with?(search_value_downcase) ||
            address&.postalCode&.downcase&.start_with?(search_value_downcase) ||
            address&.country&.downcase&.start_with?(search_value_downcase)
        end
      when 'CodeableConcept'
        # FHIR token search (https://www.hl7.org/fhir/search.html#token): "When in doubt, servers SHOULD
        # treat tokens in a case-insensitive manner, on the grounds that including undesired data has
        # less safety implications than excluding desired behavior".
        codings = values_found.flat_map(&:coding)
        if search_value.include? '|'
          system = search_value.split('|').first
          code = search_value.split('|').last
          codings&.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
        else
          codings&.any? { |coding| coding.code&.casecmp?(search_value) }
        end
      when 'Coding'
        if search_value.include? '|'
          system = search_value.split('|').first
          code = search_value.split('|').last
          values_found.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
        else
          values_found.any? { |coding| coding.code&.casecmp?(search_value) }
        end
      when 'Identifier'
        if search_value.include? '|'
          values_found.any? { |identifier| "#{identifier.system}|#{identifier.value}" == search_value }
        else
          values_found.any? { |identifier| identifier.value == search_value }
        end
      when 'string'
        searched_values = search_value.downcase.split(/(?<!\\\\),/).map{ |string| string.gsub('\\,', ',') }
        values_found.any? do |value_found|
          searched_values.any? { |searched_value| value_found.downcase.starts_with? searched_value }
        end
      else
        # searching by patient requires special case because we are searching by a resource identifier
        # references can also be URLs, so we may need to resolve those URLs
        if ['subject', 'patient'].include? search_param_name.to_s
          id = search_value.split('Patient/').last
          possible_values = [id, "Patient/#{id}", "#{url}/Patient/#{id}"]
          values_found.any? do |reference|
            possible_values.include? reference
          end
        else
          search_values = search_value.split(/(?<!\\\\),/).map { |string| string.gsub('\\,', ',') }
          values_found.any? { |value_found| search_values.include? value_found }
        end
      end

    break if match_found
  end

  match_found
end

#search_param_paths(name) ⇒ Object



7
8
9
10
11
12
13
14
# File 'lib/us_core_test_kit/resource_search_param_checker.rb', line 7

def search_param_paths(name)
  paths = .search_definitions[name.to_sym][:paths]
  if paths.first =='class'
    paths[0] = 'local_class'
  end

  paths
end