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.
- data/Gemfile +9 -9
- data/README.md +39 -2
- data/Rakefile +25 -44
- data/js/map-reduce-utils.js +174 -0
- data/js/underscore-min.js +24 -0
- data/lib/qme/importer/code_system_helper.rb +26 -0
- data/lib/qme/importer/entry.rb +89 -0
- data/lib/qme/importer/generic_importer.rb +71 -0
- data/lib/qme/importer/hl7_helper.rb +27 -0
- data/lib/qme/importer/patient_importer.rb +150 -0
- data/lib/qme/importer/property_matcher.rb +103 -0
- data/lib/qme/importer/section_importer.rb +82 -0
- data/lib/qme/map/map_reduce_builder.rb +77 -147
- data/lib/qme/map/map_reduce_executor.rb +97 -13
- data/lib/qme/measure/database_loader.rb +90 -0
- data/lib/qme/measure/measure_loader.rb +141 -0
- data/lib/qme/mongo_helpers.rb +15 -0
- data/lib/qme/randomizer/patient_randomizer.rb +95 -0
- data/lib/qme_test.rb +13 -0
- data/lib/quality-measure-engine.rb +20 -4
- data/lib/tasks/measure.rake +76 -0
- data/lib/tasks/mongo.rake +74 -0
- data/lib/tasks/patient_random.rake +46 -0
- metadata +110 -156
- data/.gitignore +0 -6
- data/Gemfile.lock +0 -44
- data/fixtures/complex_measure.json +0 -36
- data/fixtures/result_example.json +0 -6
- data/lib/patches/v8.rb +0 -20
- data/lib/qme/query/json_document_builder.rb +0 -130
- data/lib/qme/query/json_query_executor.rb +0 -44
- data/measures/0032/0032_NQF_Cervical_Cancer_Screening.json +0 -171
- data/measures/0032/patients/denominator1.json +0 -10
- data/measures/0032/patients/denominator2.json +0 -10
- data/measures/0032/patients/numerator1.json +0 -11
- data/measures/0032/patients/population1.json +0 -9
- data/measures/0032/patients/population2.json +0 -11
- data/measures/0032/result/result.json +0 -6
- data/measures/0043/0043_NQF_PneumoniaVaccinationStatusForOlderAdults.json +0 -71
- data/measures/0043/patients/denominator.json +0 -11
- data/measures/0043/patients/numerator.json +0 -11
- data/measures/0043/patients/population.json +0 -10
- data/measures/0043/result/result.json +0 -6
- data/quality-measure-engine.gemspec +0 -97
- data/schema/result.json +0 -28
- data/schema/schema.json +0 -143
- data/spec/qme/map/map_reduce_builder_spec.rb +0 -64
- data/spec/qme/measures_spec.rb +0 -50
- data/spec/qme/query/json_document_builder_spec.rb +0 -56
- data/spec/schema_spec.rb +0 -21
- data/spec/spec_helper.rb +0 -7
- 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
|
data/spec/qme/measures_spec.rb
DELETED
@@ -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,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
|