quality-measure-engine 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/qme/map/map_reduce_builder.rb +14 -2
- data/lib/qme/map/map_reduce_executor.rb +43 -1
- data/lib/qme/quality_report.rb +10 -1
- data/lib/qme/version.rb +1 -1
- data/lib/quality-measure-engine.rb +2 -1
- data/test/fixtures/records/jane_jones_numerator.json +3 -0
- data/test/fixtures/records/jill_jones_denominator.json +6 -0
- data/test/unit/qme/map/map_reduce_builder_test.rb +9 -0
- data/test/unit/qme/map/map_reduce_executor_test.rb +39 -0
- metadata +3 -4
@@ -11,9 +11,10 @@ module QME
|
|
11
11
|
# Utility class used to supply a binding to Erb
|
12
12
|
class Context < OpenStruct
|
13
13
|
# Create a new context
|
14
|
-
# @param [Hash] vars a hash of parameter names (String) and values (Object). Each
|
14
|
+
# @param [Hash] vars a hash of parameter names (String) and values (Object). Each
|
15
|
+
# entry is added as an accessor of the new Context
|
15
16
|
def initialize(db, vars)
|
16
|
-
super(vars)
|
17
|
+
super(Context.add_defaults(vars))
|
17
18
|
@db = db
|
18
19
|
end
|
19
20
|
|
@@ -23,6 +24,17 @@ module QME
|
|
23
24
|
binding
|
24
25
|
end
|
25
26
|
|
27
|
+
# Add default parameter values if not specified
|
28
|
+
def self.add_defaults(vars)
|
29
|
+
if !vars.has_key?('enable_logging')
|
30
|
+
vars['enable_logging'] = false
|
31
|
+
end
|
32
|
+
if !vars.has_key?('enable_rationale')
|
33
|
+
vars['enable_rationale'] = false
|
34
|
+
end
|
35
|
+
vars
|
36
|
+
end
|
37
|
+
|
26
38
|
# Inserts any library code into the measure JS. JS library code is loaded from
|
27
39
|
# three locations: the js directory of the quality-measure-engine project, the
|
28
40
|
# js sub-directory of the current directory (e.g. measures/js), and the bundles
|
@@ -7,7 +7,10 @@ module QME
|
|
7
7
|
class Executor
|
8
8
|
|
9
9
|
include DatabaseAccess
|
10
|
-
|
10
|
+
SUPPLEMENTAL_DATA_ELEMENTS = {QME::QualityReport::RACE => "$value.race.code",
|
11
|
+
QME::QualityReport::ETHNICITY => "$value.ethnicity.code",
|
12
|
+
QME::QualityReport::SEX => "$value.gender",
|
13
|
+
QME::QualityReport::PAYER => "$value.payer"}
|
11
14
|
# Create a new Executor for a specific measure, effective date and patient population.
|
12
15
|
# @param [String] measure_id the measure identifier
|
13
16
|
# @param [String] sub_id the measure sub-identifier or null if the measure is single numerator
|
@@ -64,6 +67,44 @@ module QME
|
|
64
67
|
pipeline
|
65
68
|
end
|
66
69
|
|
70
|
+
|
71
|
+
#Calculate all of the supoplemental data elements
|
72
|
+
def calculate_supplemental_data_elements
|
73
|
+
|
74
|
+
match = {'value.measure_id' => @measure_id,
|
75
|
+
'value.sub_id' => @sub_id,
|
76
|
+
'value.effective_date' => @parameter_values['effective_date'],
|
77
|
+
'value.test_id' => @parameter_values['test_id'],
|
78
|
+
'value.manual_exclusion' => {'$in' => [nil, false]}}
|
79
|
+
|
80
|
+
keys = @measure_def["population_ids"].keys - [QME::QualityReport::OBSERVATION, "stratification"]
|
81
|
+
supplemental_data = Hash[*keys.map{|k| [k,{QME::QualityReport::RACE => {},
|
82
|
+
QME::QualityReport::ETHNICITY => {},
|
83
|
+
QME::QualityReport::SEX => {},
|
84
|
+
QME::QualityReport::PAYER => {}}]}.flatten]
|
85
|
+
|
86
|
+
keys.each do |pop_id|
|
87
|
+
_match = match.clone
|
88
|
+
_match["value.#{pop_id}"] = {"$gt" => 0}
|
89
|
+
SUPPLEMENTAL_DATA_ELEMENTS.each_pair do |supp_element,location|
|
90
|
+
group1 = {"$group" => { "_id" => { "id" => "$_id", "val" => location}}}
|
91
|
+
group2 = {"$group" => {"_id" => "$_id.val", "val" =>{"$sum" => 1} }}
|
92
|
+
pipeline = [{"$match" =>_match},group1,group2]
|
93
|
+
aggregate = get_db.command(:aggregate => 'patient_cache', :pipeline => pipeline)
|
94
|
+
|
95
|
+
v = {}
|
96
|
+
(aggregate["result"] || []).each do |entry|
|
97
|
+
code = entry["_id"].nil? ? "UNK" : entry["_id"]
|
98
|
+
v[code] = entry["val"]
|
99
|
+
end
|
100
|
+
supplemental_data[pop_id] ||= {}
|
101
|
+
supplemental_data[pop_id][supp_element] = v
|
102
|
+
end
|
103
|
+
end
|
104
|
+
supplemental_data
|
105
|
+
end
|
106
|
+
|
107
|
+
|
67
108
|
# Examines the patient_cache collection and generates a total of all groups
|
68
109
|
# for the measure. The totals are placed in a document in the query_cache
|
69
110
|
# collection.
|
@@ -104,6 +145,7 @@ module QME
|
|
104
145
|
result.reject! {|k, v| k == '_id'} # get rid of the group id the Mongo forced us to use
|
105
146
|
# result['exclusions'] += get_db['patient_cache'].find(base_query.merge({'value.manual_exclusion'=>true})).count
|
106
147
|
result.merge!(execution_time: (Time.now.to_i - @parameter_values['start_time'].to_i)) if @parameter_values['start_time']
|
148
|
+
result[:supplemental_data] = self.calculate_supplemental_data_elements
|
107
149
|
get_db()["query_cache"].insert(result)
|
108
150
|
get_db().command({:getLastError => 1}) # make sure last insert finished before we continue
|
109
151
|
result
|
data/lib/qme/quality_report.rb
CHANGED
@@ -18,6 +18,12 @@ module QME
|
|
18
18
|
ANTINUMERATOR = 'antinumerator'
|
19
19
|
CONSIDERED = 'considered'
|
20
20
|
|
21
|
+
RACE = 'RACE'
|
22
|
+
ETHNICITY = 'ETHNICITY'
|
23
|
+
SEX ='SEX'
|
24
|
+
POSTAL_CODE = 'POSTAL_CODE'
|
25
|
+
PAYER = 'PAYER'
|
26
|
+
|
21
27
|
# Gets rid of all calculated QualityReports by dropping the patient_cache
|
22
28
|
# and query_cache collections
|
23
29
|
def self.destroy_all
|
@@ -144,11 +150,14 @@ module QME
|
|
144
150
|
filters.each {|key, value| value.sort_by! {|v| (v.is_a? Hash) ? "#{v}" : v} if value.is_a? Array} unless filters.nil?
|
145
151
|
end
|
146
152
|
|
147
|
-
def patient_result
|
153
|
+
def patient_result(patient_id = nil)
|
148
154
|
cache = get_db()["patient_cache"]
|
149
155
|
query = {'value.measure_id' => @measure_id, 'value.sub_id' => @sub_id,
|
150
156
|
'value.effective_date' => @parameter_values['effective_date'],
|
151
157
|
'value.test_id' => @parameter_values['test_id']}
|
158
|
+
if patient_id
|
159
|
+
query['value.medical_record_id'] = patient_id
|
160
|
+
end
|
152
161
|
cache.find(query).first()
|
153
162
|
end
|
154
163
|
|
data/lib/qme/version.rb
CHANGED
@@ -8,13 +8,14 @@ require 'rubyXL'
|
|
8
8
|
require "qme/version"
|
9
9
|
require 'qme/database_access'
|
10
10
|
require 'qme/quality_measure'
|
11
|
+
require 'qme/quality_report'
|
11
12
|
|
12
13
|
require 'qme/map/map_reduce_builder'
|
13
14
|
require 'qme/map/map_reduce_executor'
|
14
15
|
require 'qme/map/measure_calculation_job'
|
15
16
|
require 'qme/map/cv_aggregator'
|
16
17
|
|
17
|
-
|
18
|
+
|
18
19
|
|
19
20
|
require 'qme/bundle/eh_measure_sheet'
|
20
21
|
require 'qme/bundle/eh_patient_importer'
|
@@ -2,6 +2,12 @@
|
|
2
2
|
"_id": "507ec1407042f9362c000017",
|
3
3
|
"birthdate": 946715400,
|
4
4
|
"medical_record_number" : "1236",
|
5
|
+
"race" : { "code" : "1002-5",
|
6
|
+
"name" : "American Indian or Alaska Native",
|
7
|
+
"codeSystem" : "CDC Race" },
|
8
|
+
"ethnicity" : { "code" : "2186-5",
|
9
|
+
"name" : "Not Hispanic or Latino",
|
10
|
+
"codeSystem" : "CDC Race" },
|
5
11
|
"conditions": [
|
6
12
|
{
|
7
13
|
"codes": {
|
@@ -35,5 +35,14 @@ class MapReduceBuilderTest < MiniTest::Unit::TestCase
|
|
35
35
|
binding = context.get_binding
|
36
36
|
assert_equal 10, eval("a",binding)
|
37
37
|
assert_equal 20, eval("b",binding)
|
38
|
+
assert_equal false, eval("enable_logging",binding)
|
39
|
+
vars = {'enable_logging'=>true}
|
40
|
+
context = QME::MapReduce::Builder::Context.new(get_db(), vars)
|
41
|
+
binding = context.get_binding
|
42
|
+
assert_equal true, eval("enable_logging",binding)
|
43
|
+
vars = {'enable_logging'=>false}
|
44
|
+
context = QME::MapReduce::Builder::Context.new(get_db(), vars)
|
45
|
+
binding = context.get_binding
|
46
|
+
assert_equal false, eval("enable_logging",binding)
|
38
47
|
end
|
39
48
|
end
|
@@ -18,6 +18,7 @@ class MapReduceExecutorTest < MiniTest::Unit::TestCase
|
|
18
18
|
'effective_date' => Time.gm(2011, 1, 15).to_i)
|
19
19
|
|
20
20
|
executor.map_records_into_measure_groups
|
21
|
+
|
21
22
|
|
22
23
|
assert_equal 4, get_db['patient_cache'].find().count
|
23
24
|
assert_equal 3, get_db['patient_cache'].find("value.#{QME::QualityReport::POPULATION}" => 1).count
|
@@ -26,6 +27,44 @@ class MapReduceExecutorTest < MiniTest::Unit::TestCase
|
|
26
27
|
assert_equal 1, get_db['patient_cache'].find("value.#{QME::QualityReport::NUMERATOR}" => 1).count
|
27
28
|
end
|
28
29
|
|
30
|
+
|
31
|
+
def test_calculate_supplemental_data_elements
|
32
|
+
executor = QME::MapReduce::Executor.new("2E679CD2-3FEC-4A75-A75A-61403E5EFEE8", nil,
|
33
|
+
'effective_date' => Time.gm(2011, 1, 15).to_i)
|
34
|
+
|
35
|
+
executor.map_records_into_measure_groups
|
36
|
+
executor.count_records_in_measure_groups
|
37
|
+
assert_equal 1, get_db['query_cache'].find().count
|
38
|
+
doc = get_db['query_cache'].find().first
|
39
|
+
suppl = doc["supplemental_data"]
|
40
|
+
assert !suppl.empty?, "should contain supplemental data entries"
|
41
|
+
ipp = {QME::QualityReport::RACE =>{"UNK"=>2, "1002-5"=>1},
|
42
|
+
QME::QualityReport::ETHNICITY => {"UNK"=>1, "2186-5"=>2},
|
43
|
+
QME::QualityReport::PAYER => {"UNK"=>3},
|
44
|
+
QME::QualityReport::SEX => {"F"=>2,"M"=>1}
|
45
|
+
}
|
46
|
+
|
47
|
+
denom = {QME::QualityReport::RACE =>{"UNK"=>1, "1002-5"=>1},
|
48
|
+
QME::QualityReport::ETHNICITY => { "2186-5"=>2},
|
49
|
+
QME::QualityReport::PAYER => {"UNK"=>2},
|
50
|
+
QME::QualityReport::SEX => {"F"=>2}
|
51
|
+
}
|
52
|
+
|
53
|
+
numer = {QME::QualityReport::RACE =>{"UNK"=>1},
|
54
|
+
QME::QualityReport::ETHNICITY => {"2186-5"=>1},
|
55
|
+
QME::QualityReport::PAYER => {"UNK"=>1},
|
56
|
+
QME::QualityReport::SEX => {"F"=>1}
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
assert_equal ipp, suppl[QME::QualityReport::POPULATION]
|
62
|
+
assert_equal denom, suppl[QME::QualityReport::DENOMINATOR]
|
63
|
+
assert_equal numer, suppl[QME::QualityReport::NUMERATOR]
|
64
|
+
|
65
|
+
|
66
|
+
end
|
67
|
+
|
29
68
|
def test_count_records_in_measure_groups
|
30
69
|
executor = QME::MapReduce::Executor.new("2E679CD2-3FEC-4A75-A75A-61403E5EFEE8", nil,
|
31
70
|
'effective_date' => Time.gm(2011, 1, 15).to_i)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quality-measure-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2013-
|
16
|
+
date: 2013-04-22 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: moped
|
@@ -232,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
232
232
|
version: '0'
|
233
233
|
requirements: []
|
234
234
|
rubyforge_project:
|
235
|
-
rubygems_version: 1.8.
|
235
|
+
rubygems_version: 1.8.25
|
236
236
|
signing_key:
|
237
237
|
specification_version: 3
|
238
238
|
summary: This library can run JavaScript based clinical quality measures on a repository
|
@@ -264,4 +264,3 @@ test_files:
|
|
264
264
|
- test/unit/qme/map/measure_calculation_job_test.rb
|
265
265
|
- test/unit/qme/quality_measure_test.rb
|
266
266
|
- test/unit/qme/quality_report_test.rb
|
267
|
-
has_rdoc:
|