Class: MedicalRecords::LighthouseClient
- Inherits:
-
Common::Client::Base
- Object
- Common::Client::Base
- MedicalRecords::LighthouseClient
- Defined in:
- lib/medical_records/lighthouse_client.rb
Overview
Core class responsible for Medical Records API interface operations with the Lighthouse FHIR server.
Instance Method Summary collapse
- #authenticate ⇒ Object
-
#fetch_nested_value(object, field_path) ⇒ Object
protected
Fetches the value of a potentially nested field from a given object.
- #get_allergy(allergy_id) ⇒ Object
- #handle_api_errors(result) ⇒ Object protected
-
#initialize(icn) ⇒ LighthouseClient
constructor
Initialize the client.
- #lighthouse_client ⇒ Object
- #list_allergies ⇒ Object
- #list_vitals(from_date = nil, to_date = nil) ⇒ Object
- #measure_duration(event: 'default', tags: []) ⇒ Object protected
-
#merge_bundles(bundle1, bundle2) ⇒ Object
protected
Merge two FHIR bundles into one, with an updated total count.
-
#paginate_bundle_entries(entries, page_size, page_num) ⇒ Object
protected
Apply pagination to the entries in a FHIR::Bundle object.
-
#sort_bundle(bundle, field, order = :asc) ⇒ Object
protected
Sort the FHIR::Bundle entries on a given field and sort order.
-
#sort_bundle_with_criteria(bundle, order = :asc) ⇒ Object
protected
Sort the FHIR::Bundle entries based on a provided block.
Methods inherited from Common::Client::Base
#config, configuration, #connection, #delete, #get, #perform, #post, #put, #raise_backend_exception, #raise_not_authenticated, #request, #sanitize_headers!, #service_name
Methods included from SentryLogging
#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata
Constructor Details
#initialize(icn) ⇒ LighthouseClient
Initialize the client
16 17 18 19 20 21 22 |
# File 'lib/medical_records/lighthouse_client.rb', line 16 def initialize(icn) super() raise Common::Exceptions::ParameterMissing, 'ICN' if icn.blank? @icn = icn end |
Instance Method Details
#authenticate ⇒ Object
28 29 30 31 32 |
# File 'lib/medical_records/lighthouse_client.rb', line 28 def authenticate # FIXME: Explore doing this in a less janky way. # This is called by the MHV Controller Concern, but is not needed for this client # because it is handled in Lighthouse::VeteransHealth::Client::retrieve_bearer_token end |
#fetch_nested_value(object, field_path) ⇒ Object (protected)
Fetches the value of a potentially nested field from a given object.
164 165 166 167 168 |
# File 'lib/medical_records/lighthouse_client.rb', line 164 def fetch_nested_value(object, field_path) field_path.split('.').reduce(object) do |obj, method| obj.respond_to?(method) ? obj.send(method) : nil end end |
#get_allergy(allergy_id) ⇒ Object
48 49 50 51 |
# File 'lib/medical_records/lighthouse_client.rb', line 48 def get_allergy(allergy_id) bundle = lighthouse_client.get_allergy_intolerance(allergy_id) Oj.load(bundle[:body].to_json, symbol_keys: true) end |
#handle_api_errors(result) ⇒ Object (protected)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/medical_records/lighthouse_client.rb', line 55 def handle_api_errors(result) if result.code.present? && result.code >= 400 body = JSON.parse(result.body) diagnostics = body['issue']&.first&.fetch('diagnostics', nil) diagnostics = "Error fetching data#{": #{diagnostics}" if diagnostics}" # Special-case exception handling if result.code == 500 && diagnostics.include?('HAPI-1363') # "HAPI-1363: Either No patient or multiple patient found" raise MedicalRecords::PatientNotFound end # Default exception handling raise Common::Exceptions::BackendServiceException.new( "MEDICALRECORDS_#{result.code}", status: result.code, detail: diagnostics, source: self.class.to_s ) end end |
#lighthouse_client ⇒ Object
24 25 26 |
# File 'lib/medical_records/lighthouse_client.rb', line 24 def lighthouse_client @lighthouse_client ||= Lighthouse::VeteransHealth::Client.new(@icn) end |
#list_allergies ⇒ Object
42 43 44 45 46 |
# File 'lib/medical_records/lighthouse_client.rb', line 42 def list_allergies bundle = lighthouse_client.list_allergy_intolerances bundle = Oj.load(bundle[:body].to_json, symbol_keys: true) sort_bundle(bundle, :recordedDate, :desc) end |
#list_vitals(from_date = nil, to_date = nil) ⇒ Object
34 35 36 37 38 39 40 |
# File 'lib/medical_records/lighthouse_client.rb', line 34 def list_vitals(from_date = nil, to_date = nil) params = { category: 'vital-signs' } params[:date] = ["ge#{from_date}", "le#{to_date}"] if from_date && to_date bundle = lighthouse_client.list_observations(params) bundle = Oj.load(bundle[:body].to_json, symbol_keys: true) sort_bundle(bundle, :recordedDate, :desc) end |
#measure_duration(event: 'default', tags: []) ⇒ Object (protected)
170 171 172 173 174 175 176 177 178 179 |
# File 'lib/medical_records/lighthouse_client.rb', line 170 def measure_duration(event: 'default', tags: []) # Use time since boot to avoid clock skew issues # https://github.com/sidekiq/sidekiq/issues/3999 start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) result = yield duration = (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start_time).round(4) StatsD.measure("api.mhv.lighthouse.#{event}.duration", duration, tags:) result end |
#merge_bundles(bundle1, bundle2) ⇒ Object (protected)
Merge two FHIR bundles into one, with an updated total count.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/medical_records/lighthouse_client.rb', line 84 def merge_bundles(bundle1, bundle2) unless bundle1.resourceType == 'Bundle' && bundle2.resourceType == 'Bundle' raise 'Both inputs must be FHIR Bundles' end # Clone the first bundle to avoid modifying the original merged_bundle = bundle1.clone # Merge the entries from the second bundle into the merged_bundle merged_bundle.entry ||= [] bundle2.entry&.each do |entry| merged_bundle.entry << entry end # Update the total count in the merged bundle merged_bundle.total = merged_bundle.entry.count merged_bundle end |
#paginate_bundle_entries(entries, page_size, page_num) ⇒ Object (protected)
Apply pagination to the entries in a FHIR::Bundle object. This assumes sorting has already taken place.
111 112 113 114 115 116 117 118 |
# File 'lib/medical_records/lighthouse_client.rb', line 111 def paginate_bundle_entries(entries, page_size, page_num) start_index = (page_num - 1) * page_size end_index = start_index + page_size paginated_entries = entries[start_index...end_index] # Return the paginated result or an empty array if no entries paginated_entries || [] end |
#sort_bundle(bundle, field, order = :asc) ⇒ Object (protected)
Sort the FHIR::Bundle entries on a given field and sort order. If a field is not present, that entry is sorted to the end.
128 129 130 131 132 133 |
# File 'lib/medical_records/lighthouse_client.rb', line 128 def sort_bundle(bundle, field, order = :asc) field = field.to_s sort_bundle_with_criteria(bundle, order) do |resource| fetch_nested_value(resource, field) end end |
#sort_bundle_with_criteria(bundle, order = :asc) ⇒ Object (protected)
Sort the FHIR::Bundle entries based on a provided block. The block should handle different resource types and define how to extract the sorting value from each.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/medical_records/lighthouse_client.rb', line 142 def sort_bundle_with_criteria(bundle, order = :asc) sorted_entries = bundle[:entry].sort do |entry1, entry2| value1 = yield(entry1[:resource]) value2 = yield(entry2[:resource]) if value2.nil? -1 elsif value1.nil? 1 else order == :asc ? value1 <=> value2 : value2 <=> value1 end end bundle[:entry] = sorted_entries bundle end |