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)
    unpack_and_store_valuesets(zip_file, bundle)
    unpack_and_store_results(zip_file, options[:type], measure_ids, bundle)

  end

  bundle
end

.report_progress(label, percent) ⇒ Object



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

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" => Moped::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



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

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| 
      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
151
152
# 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])
  bulk = []
  entries.each_with_index do |entry, index|
    vs = HealthDataStandards::SVS::ValueSet.new(unpack_json(entry))
    vs['bundle_id'] = bundle.id
    bulk << vs
    report_progress('Value Sets', (index*100/entries.length)) if index%10 == 0
  end
  HealthDataStandards::SVS::ValueSet.collection.insert(bulk.map {|vs| vs.as_document})
  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



174
175
176
# File 'lib/health-data-standards/import/bundle/importer.rb', line 174

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