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