quality-measure-engine 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|