Class: HealthDataStandards::Import::Bundle::Importer

Inherits:
Object
  • Object
show all
Defined in:
lib/health-data-standards/import/bundle/importer.rb

Constant Summary collapse

SOURCE_ROOTS =
{bundle: 'bundle.json',
libraries: File.join('library_functions','*.js'),
measures: 'measures', results: 'results',
valuesets: File.join('value_sets','json','*.json'),
patients: 'patients'}
COLLECTION_NAMES =
["bundles", "records", "measures", "selected_measures", "patient_cache", "query_cache", "system.js"]
CLEAR_ONLY_COLLECTIONS =
["system.js"]
DEFAULTS =
{type: nil,
  delete_existing: false,
  update_measures: true,
  clear_collections: COLLECTION_NAMES
}

Class Method Summary collapse

Class Method Details

.entry_key(original, extension) ⇒ Object

A utility function for finding files in a bundle. Strip a file path of it’s extension and just give the filename.

Parameters:

  • original (String)

    A file path.

  • extension (String)

    A file extension.

Returns:

  • The filename at the end of the original String path with the extension removed. e.g. “/boo/urns.html” -> “urns”



88
89
90
# File 'lib/health-data-standards/import/bundle/importer.rb', line 88

def self.entry_key(original, extension)
  original.split('/').last.gsub(".#{extension}", '')
end

.import(zip, options = {}) ⇒ Object

Import a quality bundle into the database. This includes metadata, measures, test patients, supporting JS libraries, and expected results.

Parameters:

  • zip (File)

    The bundle zip file.

  • Type (String)

    of measures to import, either ‘ep’, ‘eh’ or nil for all

  • keep_existing (Boolean)

    If true, delete all current collections related to patients and measures.



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
62
63
64
65
66
# File 'lib/health-data-standards/import/bundle/importer.rb', line 26

def self.import(zip,  options={})
  options = DEFAULTS.merge(options)

  bundle = nil
  Zip::ZipFile.open(zip.path) do |zip_file|

    bundle = unpack_bundle(zip_file)

    bundle_versions = Hash[* HealthDataStandards::CQM::Bundle.where({}).collect{|b| [b._id, b.version]}.flatten]
    if bundle_versions.invert[bundle.version] && !(options[:delete_existing])
      raise "A bundle with version #{bundle.version} already exists in the database. "
    end

    HealthDataStandards::CQM::Bundle.where({:version => bundle.version}).each do |b|
      puts "deleting existing bundle version: #{b.version}"
      b.delete
    end if options[:delete_existing]

    #find the highest bundle version and see if one is installed that is greater than the one
    # we are currently installing.  Do not load the libs other wise
    vers = bundle_versions.values.sort.reverse[0]
    if (vers.nil? || vers <= bundle.version || options["force_js_install"])
      unpack_and_store_system_js(zip_file)
    else
      puts "javascript libraries will not being updated as a more recent bundle version is already installed"
    end
    # Store the bundle metadata.
    unless bundle.save
      raise bundle.errors.full_messages.join(",")
    end
    puts "bundle metadata unpacked..."

    measure_ids = unpack_and_store_measures(zip_file, options[:type], bundle, options[:update_measures])
    unpack_and_store_patients(zip_file, options[:type], bundle) unless options[:exclude_results]
    unpack_and_store_valuesets(zip_file, bundle)
    unpack_and_store_results(zip_file, options[:type], measure_ids, bundle) unless options[:exclude_results]

  end

  bundle
end

.report_progress(label, percent) ⇒ Object



184
185
186
187
# File 'lib/health-data-standards/import/bundle/importer.rb', line 184

def self.report_progress(label, percent)
  print "\rLoading: #{label} #{percent}% complete"
  STDOUT.flush
end

.save_system_js_fn(name, fn) ⇒ Object

Save a javascript function into Mongo’s system.js collection for measure execution.

Parameters:

  • name (String)

    The name by which the function will be referred.

  • fn (String)

    The body of the function being saved.



73
74
75
76
77
78
79
80
81
# File 'lib/health-data-standards/import/bundle/importer.rb', line 73

def self.save_system_js_fn(name, fn)
  fn = "function () {\n #{fn} \n }"
  Mongoid.default_session['system.js'].find('_id' => name).upsert(
    {
      "_id" => name,
      "value" => BSON::Code.new(fn)
    }
  )
end

.unpack_and_store_measures(zip, type, bundle, update_measures) ⇒ Object



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
# File 'lib/health-data-standards/import/bundle/importer.rb', line 104

def self.unpack_and_store_measures(zip, type, bundle, update_measures)
  measure_ids = []
  entries = zip.glob(File.join(SOURCE_ROOTS[:measures],type || '**','*.json'))
  entries.each_with_index do |entry, index|
    source_measure = unpack_json(entry)
    # we clone so that we have a source without a bundle id
    measure = source_measure.clone
    measure_ids << measure['id']
    measure['bundle_id'] = bundle.id
    Mongoid.default_session["measures"].insert(measure)

    if update_measures
      Mongoid.default_session["measures"].where({hqmf_id: measure["hqmf_id"], sub_id: measure["sub_id"]}).each do |m|
        b = HealthDataStandards::CQM::Bundle.find(m["bundle_id"])
        if b.version < bundle.version
          m.merge!(source_measure)
          Mongoid.default_session["measures"].where({"_id" => m["_id"]}).update(m)
        end
      end
    end
    report_progress('measures', (index*100/entries.length)) if index%10 == 0
  end
  puts "\rLoading: Measures Complete          "
  measure_ids
end

.unpack_and_store_patients(zip, type, bundle) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/health-data-standards/import/bundle/importer.rb', line 130

def self.unpack_and_store_patients(zip, type, bundle)
  entries = zip.glob(File.join(SOURCE_ROOTS[:patients],type || '**','json','*.json'))
  entries.each_with_index do |entry, index|
    patient = Record.new(unpack_json(entry))
    patient['bundle_id'] = bundle.id
    patient.save
    report_progress('patients', (index*100/entries.length)) if index%10 == 0
  end
  puts "\rLoading: Patients Complete          "
end

.unpack_and_store_results(zip, type, measure_ids, bundle) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/health-data-standards/import/bundle/importer.rb', line 152

def self.unpack_and_store_results(zip, type, measure_ids, bundle)
  zip.glob(File.join(SOURCE_ROOTS[:results],'*.json')).each do |entry|
    name = Pathname.new(entry.name).basename('.json').to_s
    collection = (name == "by_patient") ? "patient_cache" : "query_cache"

    contents = unpack_json(entry)

    if (type)
      contents.select! {|entry| measure_ids.include? entry['measure_id']} if collection == 'query_cache'
      contents.select! {|entry| measure_ids.include? entry['value']['measure_id']} if collection == 'patient_cache'
    end

    contents.each do |document|
      if name == "by_patient"
        # Set the patient_id to the actual _id of
        # newly created patient record
        medical_record_id = document['value']['medical_record_id']
        if patient = Record.by_patient_id(medical_record_id).first
          document['value']['patient_id'] = patient.id
        end
      end
      document['bundle_id'] = bundle.id
      Mongoid.default_session[collection].insert(document)
    end
  end
  puts "\rLoading: Results Complete          "
end

.unpack_and_store_system_js(zip) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/health-data-standards/import/bundle/importer.rb', line 96

def self.unpack_and_store_system_js(zip)
  zip.glob(SOURCE_ROOTS[:libraries]).each do |entry|
    name = Pathname.new(entry.name).basename('.js').to_s
    contents = entry.get_input_stream.read
    save_system_js_fn(name, contents)
  end
end

.unpack_and_store_valuesets(zip, bundle) ⇒ Object



141
142
143
144
145
146
147
148
149
150
# File 'lib/health-data-standards/import/bundle/importer.rb', line 141

def self.unpack_and_store_valuesets(zip, bundle)
  entries = zip.glob(SOURCE_ROOTS[:valuesets])
  entries.each_with_index do |entry, index|
    vs = HealthDataStandards::SVS::ValueSet.new(unpack_json(entry))
    vs['bundle_id'] = bundle.id
    HealthDataStandards::SVS::ValueSet.collection.insert(vs.as_document)
    report_progress('Value Sets', (index*100/entries.length)) if index%10 == 0
  end
  puts "\rLoading: Value Sets Complete          "
end

.unpack_bundle(zip) ⇒ Object



92
93
94
# File 'lib/health-data-standards/import/bundle/importer.rb', line 92

def self.unpack_bundle(zip)
  HealthDataStandards::CQM::Bundle.new(JSON.parse(zip.read(SOURCE_ROOTS[:bundle]),max_nesting: 100))
end

.unpack_json(entry) ⇒ Object



180
181
182
# File 'lib/health-data-standards/import/bundle/importer.rb', line 180

def self.unpack_json(entry)
  JSON.parse(entry.get_input_stream.read,:max_nesting => 100)
end