Module: DaVinciCRDTestKit::GatherResponseGenerationData
- Included in:
- CustomServiceResponse, HookRequestEndpoint
- Defined in:
- lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb
Overview
Make requests to client’s FHIR server to use in building responses
Constant Summary collapse
- REFERENCES_TO_READ_BY_RESOURCE_TYPE =
{ Appointment: [ 'basedOn', 'participant.actor' ], CommunicationRequest: [ 'requester', 'sender', 'recipient' ], DeviceRequest: [ 'requester', 'performer' ], MedicationRequest: [ 'requester', 'performer', 'medicationReference', 'dispenseRequest.performer' ], NutritionOrder: [ 'orderer' ], ServiceRequest: [ 'requester', 'performer', 'locationReference' ], VisionPrescription: [ 'prescriber' ], Encounter: [ 'participant.individual', 'location.location', 'serviceProvider' ], PractitionerRole: [ 'practitioner', 'organization', 'location' ] }.freeze
Instance Method Summary collapse
- #add_location_to_hash(location, location_hash) ⇒ Object
- #add_prefetch_resource_to_resource_hash(prefetched_resource, resource_hash) ⇒ Object
- #analyzed_resources ⇒ Object
- #data_request_headers ⇒ Object
- #entry_has_required_details?(entry) ⇒ Boolean
- #execute_request(query) ⇒ Object
- #extract_bundle_entries(bundle) ⇒ Object
- #fetch_reference(reference, additional_tag: nil, parse_as_fhir: false) ⇒ Object
- #fhir_server_connection ⇒ Object
- #find_coverage_for_request ⇒ Object
- #find_references_to_read(resource, to_read_list) ⇒ Object
- #gather_appointment_book_data ⇒ Object
- #gather_data_for_request(to_read_list, to_analyze_list) ⇒ Object
- #gather_encounter_discharge_data ⇒ Object
- #gather_encounter_start_data ⇒ Object
- #gather_order_dispatch_data ⇒ Object
- #gather_order_select_data ⇒ Object
- #gather_order_sign_data ⇒ Object
-
#get_literal_reference_values(resource, path) ⇒ Object
Precondition: at most one level of nesting in the path.
- #hook_instance_data_fetch_tag ⇒ Object
-
#normalize_reference(reference) ⇒ Object
turn absolute references into relative if for the fhir server indicated in the request.
- #persist_query_request(response, tags) ⇒ Object
- #prefetched_coverage ⇒ Object
- #prefetched_coverage_resource ⇒ Object
- #prefetched_location_bundle ⇒ Object
- #prefetched_locations_and_parents_hash ⇒ Object
- #prefetched_resources ⇒ Object
- #query_for_coverages ⇒ Object
- #read_and_analyze(reference, to_read_list) ⇒ Object
-
#request_additional_fhir_data ⇒ Object
gather additional fhir resources not requested via prefetch not used for response generation, but verified later.
- #request_coverage ⇒ Object
- #request_coverage_payer ⇒ Object
- #request_parent_locations ⇒ Object
- #resource_has_required_details?(resource) ⇒ Boolean
Instance Method Details
#add_location_to_hash(location, location_hash) ⇒ Object
395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 395 def add_location_to_hash(location, location_hash) return unless location.is_a?(FHIR::Location) && location.id.present? relative_reference = "#{location.resourceType}/#{location.id}" return if location_hash.key?(relative_reference) location_hash[relative_reference] = location return unless location.partOf&.reference.present? parent_location = fetch_reference(location.partOf.reference, additional_tag: PARENT_LOCATION_FETCH_TAG, parse_as_fhir: true) add_location_to_hash(parent_location, location_hash) end |
#add_prefetch_resource_to_resource_hash(prefetched_resource, resource_hash) ⇒ Object
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 325 def add_prefetch_resource_to_resource_hash(prefetched_resource, resource_hash) if prefetched_resource['resourceType'] == 'Bundle' prefetched_resource['entry']&.each do |entry| next unless entry_has_required_details?(entry) one_resource = entry['resource'] key = "#{one_resource['resourceType']}/#{one_resource['id']}" resource_hash[key] = one_resource end elsif resource_has_required_details?(prefetched_resource) key = "#{prefetched_resource['resourceType']}/#{prefetched_resource['id']}" resource_hash[key] = prefetched_resource end end |
#analyzed_resources ⇒ Object
308 309 310 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 308 def analyzed_resources @analyzed_resources ||= {} end |
#data_request_headers ⇒ Object
265 266 267 268 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 265 def data_request_headers @data_request_headers ||= { 'Authorization' => "Bearer #{request_body['fhirAuthorization']['access_token']}" } end |
#entry_has_required_details?(entry) ⇒ Boolean
341 342 343 344 345 346 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 341 def entry_has_required_details?(entry) entry.present? && entry.is_a?(Hash) && entry['resource'].present? && resource_has_required_details?(entry['resource']) end |
#execute_request(query) ⇒ Object
270 271 272 273 274 275 276 277 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 270 def execute_request(query) fhir_server_connection&.get(query) rescue Faraday::Error => e # Warning: This is a hack. If there is an error with the request such that we never get a response, we have # no clean way to persist that information for the Inferno test to check later. The solution here # is to persist the request anyway with a status of nil, using the error message as response body Faraday::Response.new(response_body: e., url: fhir_server_connection.url_prefix.to_s) end |
#extract_bundle_entries(bundle) ⇒ Object
133 134 135 136 137 138 139 140 141 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 133 def extract_bundle_entries(bundle) return [] unless bundle.present? && bundle.is_a?(Hash) && bundle['entry'].is_a?(Array) bundle['entry'].map do |entry| next unless entry.is_a?(Hash) && entry['resource'].is_a?(Hash) entry['resource'] end.compact end |
#fetch_reference(reference, additional_tag: nil, parse_as_fhir: false) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 182 def fetch_reference(reference, additional_tag: nil, parse_as_fhir: false) response = execute_request(reference) return nil unless response.present? = [DATA_FETCH_TAG, hook_instance_data_fetch_tag] << additional_tag if additional_tag.present? persist_query_request(response, ) return nil unless response.status.to_s.starts_with?('2') begin parse_as_fhir ? FHIR.from_contents(response.body) : JSON.parse(response.body) rescue JSON::ParserError nil end end |
#fhir_server_connection ⇒ Object
255 256 257 258 259 260 261 262 263 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 255 def fhir_server_connection @fhir_server_connection ||= if request_body['fhirServer'].present? && request_body['fhirAuthorization'].present? && request_body['fhirAuthorization']['access_token'].present? Faraday.new(url: request_body['fhirServer'], request: { open_timeout: 10 }, headers: data_request_headers) end end |
#find_coverage_for_request ⇒ Object
242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 242 def find_coverage_for_request resource = if prefetched_coverage.present? prefetched_coverage else query_for_coverages end return unless resource.is_a?(FHIR::Bundle) resource.entry&.first&.resource end |
#find_references_to_read(resource, to_read_list) ⇒ Object
198 199 200 201 202 203 204 205 206 207 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 198 def find_references_to_read(resource, to_read_list) references_to_read = REFERENCES_TO_READ_BY_RESOURCE_TYPE[resource['resourceType']&.to_sym] return [] unless references_to_read.present? references_to_read.each do |target_path| get_literal_reference_values(resource, target_path).each do |reference| to_read_list << reference unless to_read_list.include?(reference) end end end |
#gather_appointment_book_data ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 53 def gather_appointment_book_data appointment_book_to_read = [] patient_id = request_body.dig('context', 'patientId') encounter_id = request_body.dig('context', 'encounterId') user_id = request_body.dig('context', 'userId') appointment_book_to_read << "Patient/#{patient_id}" if patient_id.present? appointment_book_to_read << "Encounter/#{encounter_id}" if encounter_id.present? appointment_book_to_read << user_id if user_id.present? appointment_book_to_analyze = extract_bundle_entries(request_body.dig('context', 'appointments')) gather_data_for_request(appointment_book_to_read, appointment_book_to_analyze) end |
#gather_data_for_request(to_read_list, to_analyze_list) ⇒ Object
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 143 def gather_data_for_request(to_read_list, to_analyze_list) to_analyze_list.each do |resource| next unless resource.present? find_references_to_read(resource, to_read_list) analyzed_resources["#{resource['resourceType']}/#{resource['id']}"] = resource end read_and_analyze(to_read_list.pop, to_read_list) until to_read_list.empty? end |
#gather_encounter_discharge_data ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 79 def gather_encounter_discharge_data encounter_discharge_to_read = [] patient_id = request_body.dig('context', 'patientId') encounter_id = request_body.dig('context', 'encounterId') user_id = request_body.dig('context', 'userId') encounter_discharge_to_read << "Patient/#{patient_id}" if patient_id.present? encounter_discharge_to_read << "Encounter/#{encounter_id}" if encounter_id.present? encounter_discharge_to_read << user_id if user_id.present? gather_data_for_request(encounter_discharge_to_read, []) end |
#gather_encounter_start_data ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 67 def gather_encounter_start_data encounter_start_to_read = [] patient_id = request_body.dig('context', 'patientId') encounter_id = request_body.dig('context', 'encounterId') user_id = request_body.dig('context', 'userId') encounter_start_to_read << "Patient/#{patient_id}" if patient_id.present? encounter_start_to_read << "Encounter/#{encounter_id}" if encounter_id.present? encounter_start_to_read << user_id if user_id.present? gather_data_for_request(encounter_start_to_read, []) end |
#gather_order_dispatch_data ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 121 def gather_order_dispatch_data order_dispatch_to_read = [] patient_id = request_body.dig('context', 'patientId') order_id = request_body.dig('context', 'order') performer_id = request_body.dig('context', 'performer') order_dispatch_to_read << "Patient/#{patient_id}" if patient_id.present? order_dispatch_to_read << order_id if order_id.present? order_dispatch_to_read << performer_id if performer_id.present? gather_data_for_request(order_dispatch_to_read, [request_body.dig('context', 'task')].compact) end |
#gather_order_select_data ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 91 def gather_order_select_data order_sign_to_read = [] patient_id = request_body.dig('context', 'patientId') encounter_id = request_body.dig('context', 'encounterId') user_id = request_body.dig('context', 'userId') order_sign_to_read << "Patient/#{patient_id}" if patient_id.present? order_sign_to_read << "Encounter/#{encounter_id}" if encounter_id.present? order_sign_to_read << user_id if user_id.present? order_sign_to_analyze = extract_bundle_entries(request_body.dig('context', 'draftOrders')).select do |resource| request_body.dig('context', 'selections').include?("#{resource['resourceType']}/#{resource['id']}") end gather_data_for_request(order_sign_to_read, order_sign_to_analyze) end |
#gather_order_sign_data ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 107 def gather_order_sign_data order_sign_to_read = [] patient_id = request_body.dig('context', 'patientId') encounter_id = request_body.dig('context', 'encounterId') user_id = request_body.dig('context', 'userId') order_sign_to_read << "Patient/#{patient_id}" if patient_id.present? order_sign_to_read << "Encounter/#{encounter_id}" if encounter_id.present? order_sign_to_read << user_id if user_id.present? order_sign_to_analyze = extract_bundle_entries(request_body.dig('context', 'draftOrders')) gather_data_for_request(order_sign_to_read, order_sign_to_analyze) end |
#get_literal_reference_values(resource, path) ⇒ Object
Precondition: at most one level of nesting in the path
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 210 def get_literal_reference_values(resource, path) if path.include?('.') first_element, path = path.split('.') resource = resource[first_element] end reference_objects = case resource when Hash [resource[path]].flatten when Array resource.map { |entry| entry[path] } else [] end reference_objects.map { |entry| entry['reference'] if entry.present? }.compact end |
#hook_instance_data_fetch_tag ⇒ Object
49 50 51 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 49 def hook_instance_data_fetch_tag @hook_instance_data_fetch_tag ||= TagMethods.hook_instance_data_fetch_tag(request_body['hookInstance']) end |
#normalize_reference(reference) ⇒ Object
turn absolute references into relative if for the fhir server indicated in the request
172 173 174 175 176 177 178 179 180 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 172 def normalize_reference(reference) server = "#{request_body['fhirServer']&.chomp('/')}/" if request_body['fhirServer'].present? && reference.starts_with?(server) reference[server.length..] else reference end end |
#persist_query_request(response, tags) ⇒ Object
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 279 def persist_query_request(response, ) inferno_request_headers = data_request_headers.map { |name, value| { name:, value: } } inferno_response_headers = response.headers&.map { |name, value| { name:, value: } } requests_repo.create( verb: 'GET', url: response.env.url.to_s, direction: 'outgoing', status: response.status, request_body: response.env.request_body, response_body: response.env.response_body, test_session_id: test_run.test_session_id, result_id: result.id, request_headers: inferno_request_headers, response_headers: inferno_response_headers, tags: ) end |
#prefetched_coverage ⇒ Object
233 234 235 236 237 238 239 240 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 233 def prefetched_coverage @prefetched_coverage ||= if request_body.dig('prefetch', 'coverage').present? FHIR.from_contents(request_body.dig('prefetch', 'coverage').to_json) elsif request_body.dig('prefetch', 'cov').present? FHIR.from_contents(request_body.dig('prefetch', 'cov').to_json) end end |
#prefetched_coverage_resource ⇒ Object
359 360 361 362 363 364 365 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 359 def prefetched_coverage_resource if prefetched_coverage.is_a?(FHIR::Bundle) prefetched_coverage.entry.first&.resource else prefetched_coverage end end |
#prefetched_location_bundle ⇒ Object
380 381 382 383 384 385 386 387 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 380 def prefetched_location_bundle locations_data = request_body.dig('prefetch', 'locations') || request_body.dig('prefetch', 'locs') locations = FHIR.from_contents(locations_data.to_json) if locations_data.present? return locations if locations.is_a?(FHIR::Bundle) return nil unless locations.is_a?(FHIR::Location) FHIR::Bundle.new({ entry: [FHIR::Bundle::Entry.new({ resource: locations })] }) end |
#prefetched_locations_and_parents_hash ⇒ Object
389 390 391 392 393 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 389 def prefetched_locations_and_parents_hash prefetched_location_bundle&.entry&.each_with_object({}) do |entry, hash| add_location_to_hash(entry.resource, hash) end end |
#prefetched_resources ⇒ Object
312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 312 def prefetched_resources @prefetched_resources ||= if request_body['prefetch'].blank? || !request_body['prefetch'].is_a?(Hash) {} else request_body['prefetch'].values.each_with_object({}) do |prefetched_resource, resource_hash| next unless prefetched_resource.is_a?(Hash) add_prefetch_resource_to_resource_hash(prefetched_resource, resource_hash) end end end |
#query_for_coverages ⇒ Object
297 298 299 300 301 302 303 304 305 306 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 297 def query_for_coverages query = "Coverage?patient=#{request_body.dig('context', 'patientId')}&status=active" response = execute_request(query) return nil unless response.present? persist_query_request(response, [DATA_FETCH_TAG, hook_instance_data_fetch_tag]) return nil unless response.status.to_s.starts_with?('2') FHIR.from_contents(response.body) end |
#read_and_analyze(reference, to_read_list) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 154 def read_and_analyze(reference, to_read_list) normalized_reference = normalize_reference(reference) return if analyzed_resources.key?(normalized_reference) resource = if prefetched_resources.key?(normalized_reference) prefetched_resources[normalized_reference] else fetch_reference(normalized_reference) end analyzed_resources[normalized_reference] = resource return unless resource.present? find_references_to_read(resource, to_read_list) end |
#request_additional_fhir_data ⇒ Object
gather additional fhir resources not requested via prefetch not used for response generation, but verified later
354 355 356 357 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 354 def request_additional_fhir_data request_coverage_payer request_parent_locations end |
#request_coverage ⇒ Object
229 230 231 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 229 def request_coverage @request_coverage ||= find_coverage_for_request end |
#request_coverage_payer ⇒ Object
367 368 369 370 371 372 373 374 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 367 def request_coverage_payer return unless prefetched_coverage.present? coverage_resource = prefetched_coverage_resource return unless coverage_resource.present? && coverage_resource.payor.first&.reference.present? fetch_reference(coverage_resource.payor.first.reference, additional_tag: PAYER_ORG_FETCH_TAG) end |
#request_parent_locations ⇒ Object
376 377 378 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 376 def request_parent_locations prefetched_locations_and_parents_hash end |
#resource_has_required_details?(resource) ⇒ Boolean
348 349 350 |
# File 'lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb', line 348 def resource_has_required_details?(resource) resource.is_a?(Hash) && resource['resourceType'].present? && resource['id'].present? end |