quality-measure-engine 1.0.2 → 1.0.3
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 +1 -0
- data/VERSION +1 -1
- data/js/map_reduce_utils.js +3 -1
- data/lib/qme/ext/string.rb +5 -0
- data/lib/qme/importer/code_system_helper.rb +9 -13
- data/lib/qme/importer/entry.rb +3 -0
- data/lib/qme/importer/patient_importer.rb +6 -0
- data/lib/qme/importer/property_matcher.rb +2 -0
- data/lib/qme/importer/provider_importer.rb +94 -0
- data/lib/qme/map/map_reduce_executor.rb +64 -7
- data/lib/qme/map/measure_calculation_job.rb +22 -8
- data/lib/qme/quality_report.rb +67 -4
- data/lib/qme/randomizer/patient_randomizer.rb +34 -0
- data/lib/quality-measure-engine.rb +3 -0
- metadata +5 -3
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.3
|
data/js/map_reduce_utils.js
CHANGED
@@ -122,7 +122,9 @@ function() {
|
|
122
122
|
exclusions: false, antinumerator: false, patient_id: record._id,
|
123
123
|
medical_record_id: record.patient_id,
|
124
124
|
first: record.first, last: record.last, gender: record.gender,
|
125
|
-
birthdate: record.birthdate, test_id: record.test_id
|
125
|
+
birthdate: record.birthdate, test_id: record.test_id,
|
126
|
+
provider_performances: record.provider_performances,
|
127
|
+
race: record.race, ethnicity: record.ethnicity};
|
126
128
|
if (population()) {
|
127
129
|
value.population = true;
|
128
130
|
if (denominator()) {
|
@@ -12,7 +12,8 @@ module QME
|
|
12
12
|
'2.16.840.1.113883.6.104' => 'ICD-9-CM',
|
13
13
|
'2.16.840.1.113883.6.90' => 'ICD-10-CM',
|
14
14
|
'2.16.840.1.113883.6.14' => 'HCPCS',
|
15
|
-
'2.16.840.1.113883.6.59' => 'CVX'
|
15
|
+
'2.16.840.1.113883.6.59' => 'CVX',
|
16
|
+
'2.16.840.1.113883.6.238' => 'CDC-RE'
|
16
17
|
}
|
17
18
|
|
18
19
|
# Returns the name of a code system given an oid
|
@@ -22,23 +23,18 @@ module QME
|
|
22
23
|
CODE_SYSTEMS[oid] || "Unknown"
|
23
24
|
end
|
24
25
|
|
25
|
-
@@oid_map = nil
|
26
|
-
|
27
26
|
# Returns the oid for a code system given a codesystem name
|
28
27
|
# @param [String] the name of the code system
|
29
28
|
# @return [String] the oid of the code system
|
30
|
-
def self.oid_for_code_system(
|
31
|
-
|
32
|
-
@@oid_map = {}
|
33
|
-
CODE_SYSTEMS.each_pair do |oid, codesystem|
|
34
|
-
# STDERR.puts "Adding #{oid}, #{codesystem}"
|
35
|
-
@@oid_map[codesystem] = oid
|
36
|
-
end
|
37
|
-
end
|
38
|
-
# STDERR.puts "@@oid_map[#{codesystem}] = #{@@oid_map[codesystem]}"
|
39
|
-
return @@oid_map[codesystem]
|
29
|
+
def self.oid_for_code_system(code_system)
|
30
|
+
CODE_SYSTEMS.invert[code_system]
|
40
31
|
end
|
41
32
|
|
33
|
+
# Returns the whole map of OIDs to code systems
|
34
|
+
# @terurn [Hash] oids as keys, code system names as values
|
35
|
+
def self.code_systems
|
36
|
+
CODE_SYSTEMS
|
37
|
+
end
|
42
38
|
end
|
43
39
|
end
|
44
40
|
end
|
data/lib/qme/importer/entry.rb
CHANGED
@@ -14,7 +14,10 @@ module QME
|
|
14
14
|
entry = Entry.new
|
15
15
|
if event['code']
|
16
16
|
entry.add_code(event['code'], event['code_set'])
|
17
|
+
elsif event['codes']
|
18
|
+
entry.instance_eval { @codes = event['codes'] }
|
17
19
|
end
|
20
|
+
|
18
21
|
entry.time = event['time']
|
19
22
|
if event['value']
|
20
23
|
entry.set_value(event['value'], event['unit'])
|
@@ -121,6 +121,8 @@ module QME
|
|
121
121
|
patient_record['gender'] = patient_hash['gender']
|
122
122
|
patient_record['patient_id'] = patient_hash['patient_id']
|
123
123
|
patient_record['birthdate'] = patient_hash['birthdate']
|
124
|
+
patient_record['race'] = patient_hash['race']
|
125
|
+
patient_record['ethnicity'] = patient_hash['ethnicity']
|
124
126
|
patient_record['addresses'] = patient_hash['addresses']
|
125
127
|
event_hash = {}
|
126
128
|
patient_hash['events'].each do |key, value|
|
@@ -209,6 +211,10 @@ module QME
|
|
209
211
|
patient['birthdate'] = HL7Helper.timestamp_to_integer(birthdate_in_hl7ts)
|
210
212
|
gender_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:administrativeGenderCode')
|
211
213
|
patient['gender'] = gender_node['code']
|
214
|
+
race_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:raceCode')
|
215
|
+
patient['race'] = race_node['code'] if race_node
|
216
|
+
ethnicity_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:ethnicGroupCode')
|
217
|
+
patient['ethnicity'] = ethnicity_node['code'] if ethnicity_node
|
212
218
|
id_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:id')
|
213
219
|
patient['patient_id'] = id_node['extension']
|
214
220
|
end
|
@@ -46,6 +46,8 @@ module QME
|
|
46
46
|
if value
|
47
47
|
if @property_description['items']['properties']['value']['type'] == 'number'
|
48
48
|
value = value.to_f
|
49
|
+
elsif @property_description['items']['properties']['value']['type'] == 'boolean'
|
50
|
+
value = value.to_boolean
|
49
51
|
end
|
50
52
|
|
51
53
|
matching_values << {'date' => entry.as_point_in_time, 'value' => value}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "date"
|
2
|
+
require "date/delta"
|
3
|
+
|
4
|
+
module QME
|
5
|
+
module Importer
|
6
|
+
class ProviderImporter
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# Extract Healthcare Providers from C32
|
10
|
+
#
|
11
|
+
# @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
|
12
|
+
# will have the "cda" namespace registered to "urn:hl7-org:v3"
|
13
|
+
# @return [Array] an array of providers found in the document
|
14
|
+
def extract_providers(doc)
|
15
|
+
|
16
|
+
performers = doc.xpath("//cda:documentationOf/cda:serviceEvent/cda:performer")
|
17
|
+
|
18
|
+
providers = performers.map do |performer|
|
19
|
+
provider = {}
|
20
|
+
entity = performer.xpath(performer, "./cda:assignedEntity")
|
21
|
+
name = entity.xpath("./cda:assignedPerson/cda:name")
|
22
|
+
provider[:title] = extract_data(name, "./cda:prefix")
|
23
|
+
provider[:given_name] = extract_data(name, "./cda:given")
|
24
|
+
provider[:family_name] = extract_data(name, "./cda:family")
|
25
|
+
provider[:phone] = extract_data(entity, "./cda:telecom/@value") { |text| text.gsub("tel:", "") }
|
26
|
+
provider[:organization] = extract_data(entity, "./cda:representedOrganization/cda:name")
|
27
|
+
provider[:specialty] = extract_data(entity, "./cda:code/@code")
|
28
|
+
time = performer.xpath(performer, "./cda:time")
|
29
|
+
provider[:start] = extract_date(time, "./cda:low/@value")
|
30
|
+
provider[:end] = extract_date(time, "./cda:high/@value")
|
31
|
+
# NIST sample C32s use different OID for NPI vs C83, support both
|
32
|
+
npi = extract_data(entity, "./cda:id[@root='2.16.840.1.113883.4.6' or @root='2.16.840.1.113883.3.72.5.2']/@extension")
|
33
|
+
if ProviderImporter::valid_npi?(npi)
|
34
|
+
provider[:npi] = npi
|
35
|
+
else
|
36
|
+
puts "Warning: Invalid NPI (#{npi})"
|
37
|
+
end
|
38
|
+
provider
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def extract_date(subject,query)
|
45
|
+
date = extract_data(subject,query)
|
46
|
+
date ? Date.parse(date).to_time.to_i : nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns nil if result is an empty string, block allows text munging of result if there is one
|
50
|
+
def extract_data(subject, query)
|
51
|
+
result = subject.xpath(query).text
|
52
|
+
if result == ""
|
53
|
+
nil
|
54
|
+
elsif block_given?
|
55
|
+
yield(result)
|
56
|
+
else
|
57
|
+
result
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# validate the NPI, should be 10 or 15 digits total with the final digit being a
|
62
|
+
# checksum using the Luhn algorithm with additional special handling as described in
|
63
|
+
# https://www.cms.gov/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf
|
64
|
+
def self.valid_npi?(npi)
|
65
|
+
return false if npi.length != 10 and npi.length != 15
|
66
|
+
return false if npi.gsub(/\d/, '').length > 0 # npi must be all digits
|
67
|
+
return false if npi.length == 15 and (npi =~ /^80840/)==nil # 15 digit npi must start with 80840
|
68
|
+
|
69
|
+
# checksum is always calculated as if 80840 prefix is present
|
70
|
+
if npi.length==10
|
71
|
+
npi = '80840'+npi
|
72
|
+
end
|
73
|
+
|
74
|
+
return luhn_checksum(npi[0,14])==npi[14]
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.luhn_checksum(num)
|
78
|
+
double = {'0' => 0, '1' => 2, '2' => 4, '3' => 6, '4' => 8, '5' => 1, '6' => 3, '7' => 5, '8' => 7, '9' => 9}
|
79
|
+
sum = 0
|
80
|
+
num.reverse!
|
81
|
+
num.split("").each_with_index do |char, i|
|
82
|
+
if (i%2)==0
|
83
|
+
sum+=double[char]
|
84
|
+
else
|
85
|
+
sum+=char.to_i
|
86
|
+
end
|
87
|
+
end
|
88
|
+
sum = (9*sum)%10
|
89
|
+
|
90
|
+
return sum.to_s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -28,15 +28,31 @@ module QME
|
|
28
28
|
query = {'value.measure_id' => @measure_id, 'value.sub_id' => @sub_id,
|
29
29
|
'value.effective_date' => @parameter_values['effective_date'],
|
30
30
|
'value.test_id' => @parameter_values['test_id']}
|
31
|
+
|
32
|
+
query.merge!(filter_parameters)
|
33
|
+
|
31
34
|
result = {:measure_id => @measure_id, :sub_id => @sub_id,
|
32
35
|
:effective_date => @parameter_values['effective_date'],
|
33
|
-
:test_id => @parameter_values['test_id']}
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
:test_id => @parameter_values['test_id'], :filters => @parameter_values['filters']}
|
37
|
+
|
38
|
+
aggregate = patient_cache.group({cond: query,
|
39
|
+
initial: {population: 0, denominator: 0, numerator: 0, antinumerator: 0, exclusions: 0, considered: 0},
|
40
|
+
reduce: "function(record,sums) { for (var key in sums) { sums[key] += (record['value'][key] || key == 'considered') ? 1 : 0 } }"}).first
|
41
|
+
|
42
|
+
aggregate ||= {population: 0, denominator: 0, numerator: 0, antinumerator: 0, exclusions: 0}
|
43
|
+
aggregate.each {|key, value| aggregate[key] = value.to_i}
|
44
|
+
result.merge!(aggregate)
|
45
|
+
|
46
|
+
# need to time the old way agains the single query to verify that the single query is more performant
|
47
|
+
# %w(population denominator numerator antinumerator exclusions).each do |measure_group|
|
48
|
+
# patient_cache.find(query.merge("value.#{measure_group}" => true)) do |cursor|
|
49
|
+
# result[measure_group] = cursor.count
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
|
53
|
+
result.merge!(execution_time: (Time.now.to_i - @parameter_values['start_time'].to_i)) if @parameter_values['start_time']
|
54
|
+
|
55
|
+
get_db.collection("query_cache").save(result, safe: true)
|
40
56
|
result
|
41
57
|
end
|
42
58
|
|
@@ -52,6 +68,47 @@ module QME
|
|
52
68
|
:finalize => measure.finalize_function,
|
53
69
|
:query => {:test_id => @parameter_values['test_id']})
|
54
70
|
end
|
71
|
+
|
72
|
+
# This method runs the MapReduce job for the measure and a specific patient.
|
73
|
+
# This will create a document in the patient_cache collection. This document
|
74
|
+
# will state the measure groups that the record belongs to, such as numerator, etc.
|
75
|
+
def map_record_into_measure_groups(patient_id)
|
76
|
+
qm = QualityMeasure.new(@measure_id, @sub_id)
|
77
|
+
measure = Builder.new(get_db, qm.definition, @parameter_values)
|
78
|
+
records = get_db.collection('records')
|
79
|
+
records.map_reduce(measure.map_function, "function(key, values){return values;}",
|
80
|
+
:out => {:reduce => 'patient_cache'},
|
81
|
+
:finalize => measure.finalize_function,
|
82
|
+
:query => {:patient_id => patient_id, :test_id => @parameter_values['test_id']})
|
83
|
+
end
|
84
|
+
|
85
|
+
def filter_parameters
|
86
|
+
results = {}
|
87
|
+
conditions = []
|
88
|
+
if(filters = @parameter_values['filters'])
|
89
|
+
if (filters['providers'] && filters['providers'].size > 0)
|
90
|
+
providers = filters['providers'].map {|provider_id| BSON::ObjectId(provider_id) if provider_id }
|
91
|
+
conditions << provider_queries(providers, @parameter_values['effective_date'])
|
92
|
+
end
|
93
|
+
if (filters['races'] && filters['races'].size > 0)
|
94
|
+
conditions << {'value.race.code' => {'$in' => filters['races']}}
|
95
|
+
end
|
96
|
+
if (filters['ethnicities'] && filters['ethnicities'].size > 0)
|
97
|
+
conditions << {'value.ethnicity.code' => {'$in' => filters['ethnicities']}}
|
98
|
+
end
|
99
|
+
if (filters['genders'] && filters['genders'].size > 0)
|
100
|
+
conditions << {'value.gender' => {'$in' => filters['genders']}}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
results.merge!({'$and'=>conditions}) if conditions.length > 0
|
104
|
+
results
|
105
|
+
end
|
106
|
+
def provider_queries(provider_ids, effective_date)
|
107
|
+
{'$or' => [provider_query(provider_ids, effective_date,effective_date), provider_query(provider_ids, nil,effective_date), provider_query(provider_ids, effective_date,nil)]}
|
108
|
+
end
|
109
|
+
def provider_query(provider_ids, start_before, end_after)
|
110
|
+
{'value.provider_performances' => {'$elemMatch' => {'provider_id' => {'$in' => provider_ids}, 'start_date'=> {'$lt'=>start_before}, 'end_date'=> {'$gt'=>end_after} } }}
|
111
|
+
end
|
55
112
|
end
|
56
113
|
end
|
57
114
|
end
|
@@ -15,20 +15,34 @@ module QME
|
|
15
15
|
# the report.
|
16
16
|
class MeasureCalculationJob < Resque::JobWithStatus
|
17
17
|
def perform
|
18
|
+
MeasureCalculationJob.calculate(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.calculate(options)
|
18
22
|
test_id = options['test_id'] ? BSON::ObjectId(options['test_id']) : nil
|
19
|
-
qr = QualityReport.new(options['measure_id'], options['sub_id'], 'effective_date' => options['effective_date'], 'test_id' => test_id)
|
23
|
+
qr = QualityReport.new(options['measure_id'], options['sub_id'], 'effective_date' => options['effective_date'], 'test_id' => test_id, 'filters' => options['filters'])
|
20
24
|
if qr.calculated?
|
21
|
-
completed("#{options['measure_id']}#{options['sub_id']} has already been calculated")
|
25
|
+
completed("#{options['measure_id']}#{options['sub_id']} has already been calculated") if respond_to? :completed
|
22
26
|
else
|
23
|
-
map = QME::MapReduce::Executor.new(options['measure_id'], options['sub_id'], 'effective_date' => options['effective_date'], 'test_id' => test_id)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
map = QME::MapReduce::Executor.new(options['measure_id'], options['sub_id'], 'effective_date' => options['effective_date'], 'test_id' => test_id, 'filters' => options['filters'], 'start_time' => Time.now.to_i)
|
28
|
+
|
29
|
+
if !qr.patients_cached?
|
30
|
+
tick('Starting MapReduce') if respond_to? :tick
|
31
|
+
map.map_records_into_measure_groups
|
32
|
+
tick('MapReduce complete') if respond_to? :tick
|
33
|
+
end
|
34
|
+
|
35
|
+
tick('Calculating group totals') if respond_to? :tick
|
28
36
|
result = map.count_records_in_measure_groups
|
29
|
-
completed("#{options['measure_id']}#{options['sub_id']}: p#{result['population']}, d#{result['denominator']}, n#{result['numerator']}, e#{result['exclusions']}")
|
37
|
+
completed("#{options['measure_id']}#{options['sub_id']}: p#{result['population']}, d#{result['denominator']}, n#{result['numerator']}, e#{result['exclusions']}") if respond_to? :completed
|
30
38
|
end
|
39
|
+
|
31
40
|
end
|
41
|
+
|
42
|
+
# This can be uncommented and changed to put the jobs on a separate queue.
|
43
|
+
# def self.queue
|
44
|
+
# :statused
|
45
|
+
# end
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
data/lib/qme/quality_report.rb
CHANGED
@@ -13,6 +13,37 @@ module QME
|
|
13
13
|
get_db.collection("query_cache").drop
|
14
14
|
get_db.collection("patient_cache").drop
|
15
15
|
end
|
16
|
+
|
17
|
+
# Removes the cached results for the patient with the supplied id and
|
18
|
+
# recalculates as necessary
|
19
|
+
def self.update_patient_results(id)
|
20
|
+
determine_connection_information
|
21
|
+
|
22
|
+
# TODO: need to wait for any outstanding calculations to complete and then prevent
|
23
|
+
# any new ones from starting until we are done.
|
24
|
+
|
25
|
+
# drop any cached measure result calculations for the modified patient
|
26
|
+
get_db.collection("patient_cache").remove('value.medical_record_id' => id)
|
27
|
+
|
28
|
+
# get a list of cached measure results for a single patient
|
29
|
+
sample_patient = get_db.collection('patient_cache').find_one()
|
30
|
+
if sample_patient
|
31
|
+
cached_results = get_db.collection('patient_cache').find({'value.patient_id' => sample_patient['value']['patient_id']})
|
32
|
+
|
33
|
+
# for each cached result (a combination of measure_id, sub_id, effective_date and test_id)
|
34
|
+
cached_results.each do |measure|
|
35
|
+
# recalculate patient_cache value for modified patient
|
36
|
+
value = measure['value']
|
37
|
+
map = QME::MapReduce::Executor.new(value['measure_id'], value['sub_id'],
|
38
|
+
'effective_date' => value['effective_date'], 'test_id' => value['test_id'])
|
39
|
+
map.map_record_into_measure_groups(id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# remove the query totals so they will be recalculated using the new results for
|
44
|
+
# the modified patient
|
45
|
+
get_db.collection("query_cache").drop
|
46
|
+
end
|
16
47
|
|
17
48
|
# Creates a new QualityReport
|
18
49
|
# @param [String] measure_id value of the measure's id field
|
@@ -33,13 +64,25 @@ module QME
|
|
33
64
|
def calculated?
|
34
65
|
! result().nil?
|
35
66
|
end
|
67
|
+
|
68
|
+
# Determines whether the patient mapping for the quality report has been
|
69
|
+
# completed
|
70
|
+
def patients_cached?
|
71
|
+
! patient_result().nil?
|
72
|
+
end
|
36
73
|
|
37
74
|
# Kicks off a background job to calculate the measure
|
38
75
|
# @return a unique id for the measure calculation job
|
39
|
-
def calculate
|
40
|
-
|
41
|
-
|
42
|
-
|
76
|
+
def calculate(asynchronous=true)
|
77
|
+
options = {'measure_id' => @measure_id, 'sub_id' => @sub_id,
|
78
|
+
'effective_date' => @parameter_values['effective_date'],
|
79
|
+
'test_id' => @parameter_values['test_id'],
|
80
|
+
'filters' => QME::QualityReport.normalize_filters(@parameter_values['filters'])}
|
81
|
+
if (asynchronous)
|
82
|
+
MapReduce::MeasureCalculationJob.create(options)
|
83
|
+
else
|
84
|
+
MapReduce::MeasureCalculationJob.calculate(options)
|
85
|
+
end
|
43
86
|
end
|
44
87
|
|
45
88
|
# Returns the status of a measure calculation job
|
@@ -57,7 +100,27 @@ module QME
|
|
57
100
|
query = {:measure_id => @measure_id, :sub_id => @sub_id,
|
58
101
|
:effective_date => @parameter_values['effective_date'],
|
59
102
|
:test_id => @parameter_values['test_id']}
|
103
|
+
if @parameter_values['filters']
|
104
|
+
query.merge!({filters: QME::QualityReport.normalize_filters(@parameter_values['filters'])})
|
105
|
+
else
|
106
|
+
query.merge!({filters: nil})
|
107
|
+
end
|
108
|
+
|
60
109
|
cache.find_one(query)
|
61
110
|
end
|
111
|
+
|
112
|
+
# make sure all filter id arrays are sorted
|
113
|
+
def self.normalize_filters(filters)
|
114
|
+
filters.each {|key, value| value.sort_by! {|v| (v.is_a? Hash) ? "#{v}" : v} if value.is_a? Array} unless filters.nil?
|
115
|
+
end
|
116
|
+
|
117
|
+
def patient_result
|
118
|
+
cache = get_db.collection("patient_cache")
|
119
|
+
query = {'value.measure_id' => @measure_id, 'value.sub_id' => @sub_id,
|
120
|
+
'value.effective_date' => @parameter_values['effective_date'],
|
121
|
+
'value.test_id' => @parameter_values['test_id']}
|
122
|
+
cache.find_one(query)
|
123
|
+
end
|
124
|
+
|
62
125
|
end
|
63
126
|
end
|
@@ -46,6 +46,40 @@ module QME
|
|
46
46
|
def gender
|
47
47
|
@genders[rand(@genders.length)]
|
48
48
|
end
|
49
|
+
|
50
|
+
# Picks a race based on 2010 census estimates
|
51
|
+
# Pacific Islander 0.2%
|
52
|
+
# American Indian 0.9%
|
53
|
+
# Asian 4.8%
|
54
|
+
# Black persons 12.6%
|
55
|
+
# Hispanic 16.3%
|
56
|
+
# White 63.7%
|
57
|
+
def race_and_ethnicity
|
58
|
+
race_percent = rand(999)
|
59
|
+
case race_percent
|
60
|
+
when 0..1
|
61
|
+
# pacific islander
|
62
|
+
{race: '2076-8', ethnicity: '2186-5'}
|
63
|
+
when 2..10
|
64
|
+
# american indian
|
65
|
+
{race: '1002-5', ethnicity: '2186-5'}
|
66
|
+
when 11..58
|
67
|
+
# asian
|
68
|
+
{race: '2028-9', ethnicity: '2186-5'}
|
69
|
+
when 59..184
|
70
|
+
# black
|
71
|
+
{race: '2054-5', ethnicity: '2186-5'}
|
72
|
+
when 185..347
|
73
|
+
# hispanic
|
74
|
+
{race: '2106-3', ethnicity: '2135-2'}
|
75
|
+
when 348..984
|
76
|
+
# white (not hispanic)
|
77
|
+
{race: '2106-3', ethnicity: '2186-5'}
|
78
|
+
when 985..999
|
79
|
+
# other
|
80
|
+
{race: '2131-1', ethnicity: '2186-5'}
|
81
|
+
end
|
82
|
+
end
|
49
83
|
|
50
84
|
# Pick a forename at random appropriate for the supplied gender
|
51
85
|
# @param [String] gender the gender 'M' or 'F'
|
@@ -2,6 +2,8 @@ require "bundler/setup"
|
|
2
2
|
|
3
3
|
require 'resque/job_with_status'
|
4
4
|
|
5
|
+
require_relative 'qme/ext/string'
|
6
|
+
|
5
7
|
require_relative 'qme/database_access'
|
6
8
|
require_relative 'qme/quality_measure'
|
7
9
|
|
@@ -24,6 +26,7 @@ require_relative 'qme/importer/hl7_helper'
|
|
24
26
|
|
25
27
|
require_relative 'qme/importer/section_importer'
|
26
28
|
require_relative 'qme/importer/generic_importer'
|
29
|
+
require_relative 'qme/importer/provider_importer'
|
27
30
|
|
28
31
|
require 'json'
|
29
32
|
require 'mongo'
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: quality-measure-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0.
|
5
|
+
version: 1.0.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Marc Hadley
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2011-
|
15
|
+
date: 2011-12-08 00:00:00 -05:00
|
16
16
|
default_executable:
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
@@ -157,12 +157,14 @@ extra_rdoc_files: []
|
|
157
157
|
|
158
158
|
files:
|
159
159
|
- lib/qme/database_access.rb
|
160
|
+
- lib/qme/ext/string.rb
|
160
161
|
- lib/qme/importer/code_system_helper.rb
|
161
162
|
- lib/qme/importer/entry.rb
|
162
163
|
- lib/qme/importer/generic_importer.rb
|
163
164
|
- lib/qme/importer/hl7_helper.rb
|
164
165
|
- lib/qme/importer/patient_importer.rb
|
165
166
|
- lib/qme/importer/property_matcher.rb
|
167
|
+
- lib/qme/importer/provider_importer.rb
|
166
168
|
- lib/qme/importer/section_importer.rb
|
167
169
|
- lib/qme/map/map_reduce_builder.rb
|
168
170
|
- lib/qme/map/map_reduce_executor.rb
|
@@ -211,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
213
|
requirements: []
|
212
214
|
|
213
215
|
rubyforge_project:
|
214
|
-
rubygems_version: 1.
|
216
|
+
rubygems_version: 1.6.2
|
215
217
|
signing_key:
|
216
218
|
specification_version: 3
|
217
219
|
summary: A library for extracting quality measure information from HITSP C32's and ASTM CCR's
|