quality-measure-engine 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/Gemfile +9 -9
  2. data/README.md +39 -2
  3. data/Rakefile +25 -44
  4. data/js/map-reduce-utils.js +174 -0
  5. data/js/underscore-min.js +24 -0
  6. data/lib/qme/importer/code_system_helper.rb +26 -0
  7. data/lib/qme/importer/entry.rb +89 -0
  8. data/lib/qme/importer/generic_importer.rb +71 -0
  9. data/lib/qme/importer/hl7_helper.rb +27 -0
  10. data/lib/qme/importer/patient_importer.rb +150 -0
  11. data/lib/qme/importer/property_matcher.rb +103 -0
  12. data/lib/qme/importer/section_importer.rb +82 -0
  13. data/lib/qme/map/map_reduce_builder.rb +77 -147
  14. data/lib/qme/map/map_reduce_executor.rb +97 -13
  15. data/lib/qme/measure/database_loader.rb +90 -0
  16. data/lib/qme/measure/measure_loader.rb +141 -0
  17. data/lib/qme/mongo_helpers.rb +15 -0
  18. data/lib/qme/randomizer/patient_randomizer.rb +95 -0
  19. data/lib/qme_test.rb +13 -0
  20. data/lib/quality-measure-engine.rb +20 -4
  21. data/lib/tasks/measure.rake +76 -0
  22. data/lib/tasks/mongo.rake +74 -0
  23. data/lib/tasks/patient_random.rake +46 -0
  24. metadata +110 -156
  25. data/.gitignore +0 -6
  26. data/Gemfile.lock +0 -44
  27. data/fixtures/complex_measure.json +0 -36
  28. data/fixtures/result_example.json +0 -6
  29. data/lib/patches/v8.rb +0 -20
  30. data/lib/qme/query/json_document_builder.rb +0 -130
  31. data/lib/qme/query/json_query_executor.rb +0 -44
  32. data/measures/0032/0032_NQF_Cervical_Cancer_Screening.json +0 -171
  33. data/measures/0032/patients/denominator1.json +0 -10
  34. data/measures/0032/patients/denominator2.json +0 -10
  35. data/measures/0032/patients/numerator1.json +0 -11
  36. data/measures/0032/patients/population1.json +0 -9
  37. data/measures/0032/patients/population2.json +0 -11
  38. data/measures/0032/result/result.json +0 -6
  39. data/measures/0043/0043_NQF_PneumoniaVaccinationStatusForOlderAdults.json +0 -71
  40. data/measures/0043/patients/denominator.json +0 -11
  41. data/measures/0043/patients/numerator.json +0 -11
  42. data/measures/0043/patients/population.json +0 -10
  43. data/measures/0043/result/result.json +0 -6
  44. data/quality-measure-engine.gemspec +0 -97
  45. data/schema/result.json +0 -28
  46. data/schema/schema.json +0 -143
  47. data/spec/qme/map/map_reduce_builder_spec.rb +0 -64
  48. data/spec/qme/measures_spec.rb +0 -50
  49. data/spec/qme/query/json_document_builder_spec.rb +0 -56
  50. data/spec/schema_spec.rb +0 -21
  51. data/spec/spec_helper.rb +0 -7
  52. data/spec/validate_measures_spec.rb +0 -21
@@ -1,64 +0,0 @@
1
- MAP_FUNCTION = <<END_OF_MAP_FN
2
- function () {
3
- var value = {i: 0, d: 0, n: 0, e: 0};
4
- if (this.birthdate<=-764985600) {
5
- value.i++;
6
- if (this.measures["0043"].encounter>=1253318400) {
7
- value.d++;
8
- if (this.measures["0043"].vaccination==true) {
9
- value.n++;
10
- } else if (false) {
11
- value.e++;
12
- value.d--;
13
- }
14
- }
15
- }
16
- emit(null, value);
17
- };
18
- END_OF_MAP_FN
19
-
20
- describe QME::MapReduce::Builder do
21
-
22
- before do
23
- raw_measure_json = File.read('measures/0043/0043_NQF_PneumoniaVaccinationStatusForOlderAdults.json')
24
- @measure_json = JSON.parse(raw_measure_json)
25
- raw_measure_json = File.read('fixtures/complex_measure.json')
26
- @complex_measure_json = JSON.parse(raw_measure_json)
27
- end
28
-
29
- it 'should extract the measure metadata' do
30
- measure = QME::MapReduce::Builder.new(@measure_json, :effective_date=>Time.gm(2010, 9, 19).to_i)
31
- measure.id.should eql('0043')
32
- end
33
- it 'should extract three parameters for measure 0043 (one provided, two calculated)' do
34
- time = Time.gm(2010, 9, 19).to_i
35
-
36
- measure = QME::MapReduce::Builder.new(@measure_json, :effective_date=>time)
37
- measure.parameters.size.should eql(3)
38
- measure.parameters.should have_key(:effective_date)
39
- measure.parameters[:effective_date].should eql(time)
40
- end
41
- it 'should raise a RuntimeError if not passed all the parameters' do
42
- lambda { QME::MapReduce::Builder.new(@measure_json) }.should
43
- raise_error(RuntimeError, 'No value supplied for measure parameter: effective_date')
44
- end
45
- it 'should calculate the calculated dates correctly' do
46
- date = Time.gm(2010, 9, 19).to_i
47
- measure = QME::MapReduce::Builder.new(@measure_json, :effective_date=>date)
48
- measure.parameters[:earliest_encounter].should eql(date-QME::MapReduce::Builder::YEAR_IN_SECONDS)
49
- end
50
- it 'should produce valid JavaScript expressions for the query components' do
51
- date = Time.gm(2010, 9, 19).to_i
52
- builder = QME::MapReduce::Builder.new(@measure_json, :effective_date=>date)
53
- builder.numerator.should eql('(this.measures["0043"].vaccination==true)')
54
- builder.denominator.should eql('(this.measures["0043"].encounter>='+builder.parameters[:earliest_encounter].to_s+')')
55
- builder.population.should eql('(this.birthdate<='+builder.parameters[:earliest_birthdate].to_s+')')
56
- builder.exception.should eql('(false)')
57
- builder.map_function.should eql(MAP_FUNCTION)
58
- builder.reduce_function.should eql(QME::MapReduce::Builder::REDUCE_FUNCTION)
59
- end
60
- it 'should handle logical combinations' do
61
- builder = QME::MapReduce::Builder.new(@complex_measure_json, {})
62
- builder.population.should eql('((this.measures["0043"].age>17)&&(this.measures["0043"].age<75)&&((this.measures["0043"].sex=="male")||(this.measures["0043"].sex=="female")))')
63
- end
64
- end
@@ -1,50 +0,0 @@
1
- describe QME::MapReduce::Executor do
2
-
3
- before do
4
- db_host = nil
5
- if ENV['TEST_DB_HOST']
6
- db_host = ENV['TEST_DB_HOST']
7
- else
8
- db_host = 'localhost'
9
- end
10
- @db = Mongo::Connection.new(db_host, 27017).db('test')
11
- @measures = Dir.glob('measures/*')
12
- end
13
-
14
- it 'should produce the expected results for each measure' do
15
- print "\n"
16
- @measures.each do |dir|
17
- # load db with measure and sample patient records
18
- files = Dir.glob(File.join(dir,'*.json'))
19
- files.size.should eql(1)
20
- measure_file = files[0]
21
- patient_files = Dir.glob(File.join(dir, 'patients', '*.json'))
22
- measure = JSON.parse(File.read(measure_file))
23
- measure_id = measure['id']
24
- print "Validating measure #{measure_id}"
25
- @db.drop_collection('measures')
26
- @db.drop_collection('records')
27
- measure_collection = @db.create_collection('measures')
28
- record_collection = @db.create_collection('records')
29
- measure_collection.save(measure)
30
- patient_files.each do |patient_file|
31
- patient = JSON.parse(File.read(patient_file))
32
- record_collection.save(patient)
33
- end
34
-
35
- # load expected results
36
- result_file = File.join(dir, 'result', 'result.json')
37
- expected = JSON.parse(File.read(result_file))
38
-
39
- # evaulate measure using Map/Reduce and validate results
40
- executor = QME::MapReduce::Executor.new(@db)
41
- result = executor.measure_result(measure_id, :effective_date=>Time.gm(2010, 9, 19).to_i)
42
- result[:population].should eql(expected['initialPopulation'])
43
- result[:numerator].should eql(expected['numerator'])
44
- result[:denominator].should eql(expected['denominator'])
45
- result[:exceptions].should eql(expected['exclusions'])
46
- print " - done\n"
47
- end
48
- end
49
-
50
- end
@@ -1,56 +0,0 @@
1
- describe QME::Query::JSONDocumentBuilder do
2
-
3
- before do
4
- raw_measure_json = File.read('measures/0043/0043_NQF_PneumoniaVaccinationStatusForOlderAdults.json')
5
- @measure_json = JSON.parse(raw_measure_json)
6
- raw_measure_json = File.read('fixtures/complex_measure.json')
7
- @complex_measure_json = JSON.parse(raw_measure_json)
8
- end
9
-
10
- it 'should calculate dates for a measure' do
11
- jdb = QME::Query::JSONDocumentBuilder.new(@measure_json)
12
- jdb.parameters = {:effective_date => 1287685441}
13
- jdb.calculate_dates
14
- jdb.calculated_dates['earliest_birthdate'].should == -762154559
15
- end
16
-
17
- it 'should create a query for a simple measure' do
18
- jdb = QME::Query::JSONDocumentBuilder.new(@measure_json, {:effective_date => 1287685441})
19
- query_hash = jdb.create_query(@measure_json['denominator'])
20
- query_hash.size.should be 1
21
- query_hash['measures.0043.encounter'].should_not be_nil
22
- query_hash['measures.0043.encounter']['$gte'].should == 1256149441
23
- end
24
-
25
- it 'should properly transform a property name' do
26
- jdb = QME::Query::JSONDocumentBuilder.new(@measure_json, {:effective_date => 1287685441})
27
- jdb.transform_query_property('birthdate').should == 'birthdate'
28
- jdb.transform_query_property('foo').should == 'measures.0043.foo'
29
- end
30
-
31
- it 'should properly process a query leaf when it is an expression' do
32
- jdb = QME::Query::JSONDocumentBuilder.new(@measure_json, {:effective_date => 1287685441})
33
- args = {}
34
- jdb.process_query({"encounter" => {"_gte" => "@earliest_encounter"}}, args)
35
- args.size.should be 1
36
- args['measures.0043.encounter'].should_not be_nil
37
- args['measures.0043.encounter']['$gte'].should == 1256149441
38
- end
39
-
40
- it 'should properly process a query leaf when it is a value' do
41
- jdb = QME::Query::JSONDocumentBuilder.new(@measure_json, {:effective_date => 1287685441})
42
- args = {}
43
- jdb.process_query({"encounter" => 'splat'}, args)
44
- args.size.should be 1
45
- args['measures.0043.encounter'].should_not be_nil
46
- args['measures.0043.encounter'].should == 'splat'
47
- end
48
-
49
- it 'should create a query for a complex measure' do
50
- jdb = QME::Query::JSONDocumentBuilder.new(@complex_measure_json)
51
- query_hash = jdb.create_query(@complex_measure_json['population'])
52
- query_hash['measures.0043.age']['$gt'].should == 17
53
- query_hash['measures.0043.age']['$lt'].should == 75
54
- query_hash['$or'].should have(2).items
55
- end
56
- end
data/spec/schema_spec.rb DELETED
@@ -1,21 +0,0 @@
1
- require 'json'
2
-
3
- describe JSON, 'All JSON Schemas' do
4
- it 'should conform to JSON Schema' do
5
- schema = File.open('schema/schema.json', 'rb'){|f| JSON.parse(f.read)}
6
- Dir.glob('schema/*.json').each do |schema_file|
7
- if schema_file != 'schema/schema.json' # Don't check the schema itself
8
- data = File.open(schema_file, 'rb'){|f| JSON.parse(f.read)}
9
- JSON::Schema.validate(data, schema)
10
- end
11
- end
12
- end
13
- end
14
-
15
- describe JSON, 'Result Example' do
16
- it 'should conform to the schema defined' do
17
- schema = File.open('schema/result.json', 'rb'){|f| JSON.parse(f.read)}
18
- data = File.open('fixtures/result_example.json', 'rb'){|f| JSON.parse(f.read)}
19
- JSON::Schema.validate(data, schema)
20
- end
21
- end
data/spec/spec_helper.rb DELETED
@@ -1,7 +0,0 @@
1
- require 'bundler/setup'
2
-
3
- PROJECT_ROOT = File.dirname(__FILE__) + '/../'
4
-
5
- require PROJECT_ROOT + 'lib/quality-measure-engine'
6
-
7
- Bundler.require(:test)
@@ -1,21 +0,0 @@
1
- # Validate the measure specifications and patient samples
2
-
3
- require 'json'
4
-
5
- describe JSON, 'All measure specifications' do
6
- it 'should be valid JSON' do
7
- Dir.glob('measures/*/*.json').each do |measure_file|
8
- measure = File.read(measure_file)
9
- json = JSON.parse(measure)
10
- end
11
- end
12
- end
13
-
14
- describe JSON, 'All patient samples' do
15
- it 'should be valid JSON' do
16
- Dir.glob('measures/*/patients/*.json').each do |measure_file|
17
- measure = File.read(measure_file)
18
- json = JSON.parse(measure)
19
- end
20
- end
21
- end