Class: QRDA::Cat1::PatientImporter

Inherits:
Object
  • Object
show all
Includes:
DemographicsImporter, Singleton
Defined in:
lib/qrda-import/patient_importer.rb

Overview

This class is the central location for taking a QRDA Cat 1 XML document and converting it into the processed form we store in MongoDB. The class does this by running each measure independently on the XML document

This class is a Singleton. It should be accessed by calling PatientImporter.instance

Instance Method Summary collapse

Methods included from DemographicsImporter

#code_if_present, #get_demographics

Constructor Details

#initializePatientImporter

Returns a new instance of PatientImporter.



12
13
14
15
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/qrda-import/patient_importer.rb', line 12

def initialize
  # This differs from other HDS patient importers in that sections can have multiple importers
  @data_element_importers = []
  @data_element_importers << AdverseEventImporter.new
  @data_element_importers << AllergyIntoleranceImporter.new
  @data_element_importers << AssessmentOrderImporter.new
  @data_element_importers << AssessmentPerformedImporter.new
  @data_element_importers << AssessmentRecommendedImporter.new
  @data_element_importers << CommunicationPerformedImporter.new
  @data_element_importers << DeviceOrderImporter.new
  @data_element_importers << DeviceRecommendedImporter.new
  @data_element_importers << DiagnosisImporter.new
  @data_element_importers << DiagnosticStudyOrderImporter.new
  @data_element_importers << DiagnosticStudyPerformedImporter.new
  @data_element_importers << DiagnosticStudyRecommendedImporter.new
  @data_element_importers << EncounterOrderImporter.new
  @data_element_importers << EncounterPerformedImporter.new
  @data_element_importers << EncounterRecommendedImporter.new
  @data_element_importers << FamilyHistoryImporter.new
  @data_element_importers << ImmunizationAdministeredImporter.new
  @data_element_importers << ImmunizationOrderImporter.new
  @data_element_importers << InterventionOrderImporter.new
  @data_element_importers << InterventionPerformedImporter.new
  @data_element_importers << InterventionRecommendedImporter.new
  @data_element_importers << LaboratoryTestOrderImporter.new
  @data_element_importers << LaboratoryTestPerformedImporter.new
  @data_element_importers << LaboratoryTestRecommendedImporter.new
  @data_element_importers << MedicationActiveImporter.new
  @data_element_importers << MedicationAdministeredImporter.new
  @data_element_importers << MedicationDischargeImporter.new
  @data_element_importers << MedicationDispensedImporter.new
  @data_element_importers << MedicationOrderImporter.new
  @data_element_importers << PatientCareExperienceImporter.new
  @data_element_importers << PatientCharacteristicClinicalTrialParticipantImporter.new
  @data_element_importers << PatientCharacteristicExpiredImporter.new
  @data_element_importers << PatientCharacteristicPayerImporter.new
  @data_element_importers << PhysicalExamOrderImporter.new
  @data_element_importers << PhysicalExamPerformedImporter.new
  @data_element_importers << PhysicalExamRecommendedImporter.new
  @data_element_importers << ProcedureOrderImporter.new
  @data_element_importers << ProcedurePerformedImporter.new
  @data_element_importers << ProcedureRecommendedImporter.new
  @data_element_importers << ProgramParticipationImporter.new
  @data_element_importers << ProviderCareExperienceImporter.new
  @data_element_importers << RelatedPersonImporter.new
  @data_element_importers << SubstanceAdministeredImporter.new
  @data_element_importers << SubstanceOrderImporter.new
  @data_element_importers << SubstanceRecommendedImporter.new
  @data_element_importers << SymptomImporter.new
end

Instance Method Details

#get_patient_expired(record, doc) ⇒ Object



139
140
141
142
143
144
145
# File 'lib/qrda-import/patient_importer.rb', line 139

def get_patient_expired(record, doc)
  entry_elements = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']/cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.54']")
  return unless entry_elements.empty?

  record.expired = true
  record.deathdate = DateTime.parse(entry_elements.at_xpath("./cda:effectiveTime/cda:low")['value']).to_i
end

#import_data_elements(patient, doc, entry_id_map, codes = Set.new, codes_modifiers = {}, warnings = []) ⇒ Object



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
# File 'lib/qrda-import/patient_importer.rb', line 75

def import_data_elements(patient, doc, entry_id_map, codes = Set.new, codes_modifiers = {}, warnings = [])
  context = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']")
  nrh = NarrativeReferenceHandler.new
  nrh.build_id_map(doc)
  @data_element_importers.each do |importer|
    data_elements, id_map = importer.create_entries(context, nrh)
    new_data_elements = []

    id_map.each_pair do |key, elem_ids|
      split_id = key.split('***')
      id_string = "#{split_id[1]}(root), #{split_id[0]}(extension)"
      warnings << ValidationError.new(message: "Two or more entries share the Id: #{id_string}.") if elem_ids.length > 1
      elem_id = elem_ids.last
      data_element = data_elements.find { |de| de.id == elem_id }

      # If a data_element isn't returned, there was an issue parsing the template, provide a warning
      if data_element.nil?
        warnings << ValidationError.new(message: "Error parsing template with Id: #{id_string}.")
        next
      end

      # Keep the first element with a shared ID
      new_data_elements << data_element

      # Encounters require elements beyond id for uniqueness
      next unless data_element._type == 'QDM::EncounterPerformed'
      unique_element_keys = []
      # Add key_elements_for_determining_encounter_uniqueness to array, this is used to determine if other
      # elements with the same ID should be considered as unique
      unique_element_keys << key_elements_for_determining_encounter_uniqueness(data_element)

      # Loop through all other data elements with the same id
      elem_ids[0,elem_ids.length - 1].each do |dup_id|
        dup_element = data_elements.find { |de| de.id == dup_id }
        dup_element_keys = key_elements_for_determining_encounter_uniqueness(dup_element)
        # See if a previously selected data element shared all of the keys files
        # If all key fields match, move on.
        next if unique_element_keys.include?(dup_element_keys)
        # If all key fields don't match, keep element
        new_data_elements << dup_element
        # Add to list of unique element keys
        unique_element_keys << dup_element_keys
      end
    end

    patient.qdmPatient.dataElements << new_data_elements
    entry_id_map.merge!(id_map)
    warnings.concat(importer.warnings)
    codes.merge(importer.codes)
    codes_modifiers.merge!(importer.codes_modifiers)
    # reset warnings and codes after they're captured so that the importer can be re-used
    importer.warnings = []
    importer.codes_modifiers = {}
    importer.codes = Set.new
  end
end

#key_elements_for_determining_encounter_uniqueness(encounter) ⇒ Object



132
133
134
135
136
137
# File 'lib/qrda-import/patient_importer.rb', line 132

def key_elements_for_determining_encounter_uniqueness(encounter)
  codes = encounter.codes.collect { |dec| "#{dec.code}_#{dec.system}" }.sort.to_s
  admission_date_time = encounter&.relevantPeriod&.low.to_s
  discharge_date_time = encounter&.relevantPeriod&.high.to_s
  "#{codes}#{admission_date_time}#{discharge_date_time}"
end

#normalize_references(patient, entry_id_map, warnings) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/qrda-import/patient_importer.rb', line 147

def normalize_references(patient, entry_id_map, warnings)
  patient.qdmPatient.dataElements.each do |data_element|
    next unless data_element.respond_to?(:relatedTo) && data_element.relatedTo

    relations_to_add = []
    data_element.relatedTo.each do |related_to|
      relation_to_add = entry_id_map["#{related_to['value']}***#{related_to['namingSystem']}"]
      # Add the relation if it can be found, otherwise return a warning
      relations_to_add += relation_to_add unless relation_to_add.nil?
      if relation_to_add.nil?
        id_warning_str = "Related To Id: #{related_to['namingSystem']}(root), #{related_to['value']}(extension) cannot be found in QRDA file."
        warnings << ValidationError.new(message: id_warning_str)
      end
    end
    data_element.relatedTo = relations_to_add.map(&:to_s)
  end
end

#parse_cat1(doc) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/qrda-import/patient_importer.rb', line 63

def parse_cat1(doc)
  patient = CQM::Patient.new
  warnings = []
  codes = Set.new
  codes_modifiers = {}
  entry_id_map = {}
  import_data_elements(patient, doc, entry_id_map, codes, codes_modifiers, warnings)
  normalize_references(patient, entry_id_map, warnings)
  get_demographics(patient, doc, codes)
  [patient, warnings, codes, codes_modifiers]
end