quality-measure-engine 1.0.4 → 1.1.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 +3 -2
- data/Rakefile +0 -8
- data/VERSION +1 -1
- data/js/map_reduce_utils.js +1 -1
- data/lib/qme/database_access.rb +4 -0
- data/lib/qme/ext/record.rb +49 -0
- data/lib/qme/importer/entry.rb +1 -1
- data/lib/qme/importer/generic_importer.rb +24 -47
- data/lib/qme/importer/measure_properties_generator.rb +39 -0
- data/lib/qme/importer/provider_importer.rb +7 -4
- data/lib/qme/map/map_reduce_builder.rb +1 -1
- data/lib/qme/map/map_reduce_executor.rb +29 -25
- data/lib/qme/randomizer/patient_randomization_job.rb +5 -6
- data/lib/qme/randomizer/random_patient_creator.rb +47 -0
- data/lib/quality-measure-engine.rb +5 -8
- data/lib/tasks/patient_random.rake +3 -3
- metadata +99 -107
- data/lib/qme/ext/string.rb +0 -5
- data/lib/qme/importer/code_system_helper.rb +0 -41
- data/lib/qme/importer/hl7_helper.rb +0 -27
- data/lib/qme/importer/patient_importer.rb +0 -228
- data/lib/qme/importer/section_importer.rb +0 -138
@@ -2,8 +2,6 @@ require "bundler/setup"
|
|
2
2
|
|
3
3
|
require 'resque/job_with_status'
|
4
4
|
|
5
|
-
require_relative 'qme/ext/string'
|
6
|
-
|
7
5
|
require_relative 'qme/database_access'
|
8
6
|
require_relative 'qme/quality_measure'
|
9
7
|
|
@@ -13,20 +11,19 @@ require_relative 'qme/map/measure_calculation_job'
|
|
13
11
|
|
14
12
|
require_relative 'qme/quality_report'
|
15
13
|
|
14
|
+
require_relative 'qme/randomizer/random_patient_creator'
|
16
15
|
require_relative 'qme/randomizer/patient_randomizer'
|
17
16
|
require_relative 'qme/randomizer/patient_randomization_job'
|
18
17
|
|
19
18
|
require 'singleton'
|
19
|
+
require 'health-data-standards'
|
20
20
|
|
21
|
-
require_relative 'qme/
|
22
|
-
require_relative 'qme/importer/property_matcher'
|
23
|
-
require_relative 'qme/importer/patient_importer'
|
24
|
-
require_relative 'qme/importer/code_system_helper'
|
25
|
-
require_relative 'qme/importer/hl7_helper'
|
21
|
+
require_relative 'qme/ext/record'
|
26
22
|
|
27
|
-
require_relative 'qme/importer/
|
23
|
+
require_relative 'qme/importer/property_matcher'
|
28
24
|
require_relative 'qme/importer/generic_importer'
|
29
25
|
require_relative 'qme/importer/provider_importer'
|
26
|
+
require_relative 'qme/importer/measure_properties_generator'
|
30
27
|
|
31
28
|
require 'json'
|
32
29
|
require 'mongo'
|
@@ -28,7 +28,7 @@ namespace :patient do
|
|
28
28
|
QME::QualityMeasure.all.each_value do |measure_def|
|
29
29
|
measure_id = measure_def['id']
|
30
30
|
if !processed_measures[measure_id]
|
31
|
-
QME::Importer::
|
31
|
+
QME::Importer::MeasurePropertiesGenerator.instance.add_measure(measure_id, QME::Importer::GenericImporter.new(measure_def))
|
32
32
|
processed_measures[measure_id]=true
|
33
33
|
end
|
34
34
|
end
|
@@ -37,8 +37,8 @@ namespace :patient do
|
|
37
37
|
template = templates[rand(templates.length)]
|
38
38
|
generator = QME::Randomizer::Patient.new(template)
|
39
39
|
json = JSON.parse(generator.get())
|
40
|
-
patient_record = QME::
|
41
|
-
|
40
|
+
patient_record = QME::Randomizer::RandomPatientCreator.parse_hash(json)
|
41
|
+
patient_record.save!
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
metadata
CHANGED
@@ -1,171 +1,165 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: quality-measure-engine
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
4
5
|
prerelease:
|
5
|
-
version: 1.0.4
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Marc Hadley
|
9
9
|
- Andy Gregorowicz
|
10
10
|
- Rob Dingwell
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
|
15
|
-
date: 2011-12-16 00:00:00 -05:00
|
14
|
+
date: 2012-01-31 00:00:00.000000000 -05:00
|
16
15
|
default_executable:
|
17
|
-
dependencies:
|
18
|
-
- !ruby/object:Gem::Dependency
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
19
18
|
name: mongo
|
20
|
-
|
21
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
requirement: &2151835920 !ruby/object:Gem::Requirement
|
22
20
|
none: false
|
23
|
-
requirements:
|
21
|
+
requirements:
|
24
22
|
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version:
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '1.3'
|
27
25
|
type: :runtime
|
28
|
-
version_requirements: *id001
|
29
|
-
- !ruby/object:Gem::Dependency
|
30
|
-
name: rubyzip
|
31
26
|
prerelease: false
|
32
|
-
|
27
|
+
version_requirements: *2151835920
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rubyzip
|
30
|
+
requirement: &2151831040 !ruby/object:Gem::Requirement
|
33
31
|
none: false
|
34
|
-
requirements:
|
32
|
+
requirements:
|
35
33
|
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
34
|
+
- !ruby/object:Gem::Version
|
37
35
|
version: 0.9.4
|
38
36
|
type: :runtime
|
39
|
-
version_requirements: *id002
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: nokogiri
|
42
37
|
prerelease: false
|
43
|
-
|
38
|
+
version_requirements: *2151831040
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: nokogiri
|
41
|
+
requirement: &2151826060 !ruby/object:Gem::Requirement
|
44
42
|
none: false
|
45
|
-
requirements:
|
43
|
+
requirements:
|
46
44
|
- - ~>
|
47
|
-
- !ruby/object:Gem::Version
|
45
|
+
- !ruby/object:Gem::Version
|
48
46
|
version: 1.4.4
|
49
47
|
type: :runtime
|
50
|
-
version_requirements: *id003
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
name: resque
|
53
48
|
prerelease: false
|
54
|
-
|
49
|
+
version_requirements: *2151826060
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: resque
|
52
|
+
requirement: &2151821480 !ruby/object:Gem::Requirement
|
55
53
|
none: false
|
56
|
-
requirements:
|
54
|
+
requirements:
|
57
55
|
- - ~>
|
58
|
-
- !ruby/object:Gem::Version
|
56
|
+
- !ruby/object:Gem::Version
|
59
57
|
version: 1.15.0
|
60
58
|
type: :runtime
|
61
|
-
version_requirements: *id004
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: resque-status
|
64
59
|
prerelease: false
|
65
|
-
|
60
|
+
version_requirements: *2151821480
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: resque-status
|
63
|
+
requirement: &2151818440 !ruby/object:Gem::Requirement
|
66
64
|
none: false
|
67
|
-
requirements:
|
65
|
+
requirements:
|
68
66
|
- - ~>
|
69
|
-
- !ruby/object:Gem::Version
|
67
|
+
- !ruby/object:Gem::Version
|
70
68
|
version: 0.2.3
|
71
69
|
type: :runtime
|
72
|
-
version_requirements: *id005
|
73
|
-
- !ruby/object:Gem::Dependency
|
74
|
-
name: jsonschema
|
75
70
|
prerelease: false
|
76
|
-
|
71
|
+
version_requirements: *2151818440
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: jsonschema
|
74
|
+
requirement: &2151815160 !ruby/object:Gem::Requirement
|
77
75
|
none: false
|
78
|
-
requirements:
|
76
|
+
requirements:
|
79
77
|
- - ~>
|
80
|
-
- !ruby/object:Gem::Version
|
78
|
+
- !ruby/object:Gem::Version
|
81
79
|
version: 2.0.0
|
82
80
|
type: :development
|
83
|
-
version_requirements: *id006
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: rspec
|
86
81
|
prerelease: false
|
87
|
-
|
82
|
+
version_requirements: *2151815160
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: &2151812380 !ruby/object:Gem::Requirement
|
88
86
|
none: false
|
89
|
-
requirements:
|
87
|
+
requirements:
|
90
88
|
- - ~>
|
91
|
-
- !ruby/object:Gem::Version
|
89
|
+
- !ruby/object:Gem::Version
|
92
90
|
version: 2.5.0
|
93
91
|
type: :development
|
94
|
-
version_requirements: *id007
|
95
|
-
- !ruby/object:Gem::Dependency
|
96
|
-
name: awesome_print
|
97
92
|
prerelease: false
|
98
|
-
|
93
|
+
version_requirements: *2151812380
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: awesome_print
|
96
|
+
requirement: &2151808480 !ruby/object:Gem::Requirement
|
99
97
|
none: false
|
100
|
-
requirements:
|
98
|
+
requirements:
|
101
99
|
- - ~>
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version:
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.3'
|
104
102
|
type: :development
|
105
|
-
version_requirements: *id008
|
106
|
-
- !ruby/object:Gem::Dependency
|
107
|
-
name: roo
|
108
103
|
prerelease: false
|
109
|
-
|
104
|
+
version_requirements: *2151808480
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: roo
|
107
|
+
requirement: &2151800000 !ruby/object:Gem::Requirement
|
110
108
|
none: false
|
111
|
-
requirements:
|
109
|
+
requirements:
|
112
110
|
- - ~>
|
113
|
-
- !ruby/object:Gem::Version
|
111
|
+
- !ruby/object:Gem::Version
|
114
112
|
version: 1.9.3
|
115
113
|
type: :development
|
116
|
-
version_requirements: *id009
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
|
-
name: builder
|
119
114
|
prerelease: false
|
120
|
-
|
115
|
+
version_requirements: *2151800000
|
116
|
+
- !ruby/object:Gem::Dependency
|
117
|
+
name: builder
|
118
|
+
requirement: &2151803680 !ruby/object:Gem::Requirement
|
121
119
|
none: false
|
122
|
-
requirements:
|
120
|
+
requirements:
|
123
121
|
- - ~>
|
124
|
-
- !ruby/object:Gem::Version
|
122
|
+
- !ruby/object:Gem::Version
|
125
123
|
version: 3.0.0
|
126
124
|
type: :development
|
127
|
-
version_requirements: *id010
|
128
|
-
- !ruby/object:Gem::Dependency
|
129
|
-
name: spreadsheet
|
130
125
|
prerelease: false
|
131
|
-
|
126
|
+
version_requirements: *2151803680
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: spreadsheet
|
129
|
+
requirement: &2151912800 !ruby/object:Gem::Requirement
|
132
130
|
none: false
|
133
|
-
requirements:
|
131
|
+
requirements:
|
134
132
|
- - ~>
|
135
|
-
- !ruby/object:Gem::Version
|
133
|
+
- !ruby/object:Gem::Version
|
136
134
|
version: 0.6.5.2
|
137
135
|
type: :development
|
138
|
-
version_requirements: *id011
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: google-spreadsheet-ruby
|
141
136
|
prerelease: false
|
142
|
-
|
137
|
+
version_requirements: *2151912800
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: google-spreadsheet-ruby
|
140
|
+
requirement: &2152185860 !ruby/object:Gem::Requirement
|
143
141
|
none: false
|
144
|
-
requirements:
|
142
|
+
requirements:
|
145
143
|
- - ~>
|
146
|
-
- !ruby/object:Gem::Version
|
144
|
+
- !ruby/object:Gem::Version
|
147
145
|
version: 0.1.2
|
148
146
|
type: :development
|
149
|
-
|
150
|
-
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: *2152185860
|
149
|
+
description: A library for extracting quality measure information from HITSP C32's
|
150
|
+
and ASTM CCR's
|
151
151
|
email: talk@projectpophealth.org
|
152
152
|
executables: []
|
153
|
-
|
154
153
|
extensions: []
|
155
|
-
|
156
154
|
extra_rdoc_files: []
|
157
|
-
|
158
|
-
files:
|
155
|
+
files:
|
159
156
|
- lib/qme/database_access.rb
|
160
|
-
- lib/qme/ext/
|
161
|
-
- lib/qme/importer/code_system_helper.rb
|
157
|
+
- lib/qme/ext/record.rb
|
162
158
|
- lib/qme/importer/entry.rb
|
163
159
|
- lib/qme/importer/generic_importer.rb
|
164
|
-
- lib/qme/importer/
|
165
|
-
- lib/qme/importer/patient_importer.rb
|
160
|
+
- lib/qme/importer/measure_properties_generator.rb
|
166
161
|
- lib/qme/importer/property_matcher.rb
|
167
162
|
- lib/qme/importer/provider_importer.rb
|
168
|
-
- lib/qme/importer/section_importer.rb
|
169
163
|
- lib/qme/map/map_reduce_builder.rb
|
170
164
|
- lib/qme/map/map_reduce_executor.rb
|
171
165
|
- lib/qme/map/measure_calculation_job.rb
|
@@ -177,6 +171,7 @@ files:
|
|
177
171
|
- lib/qme/quality_report.rb
|
178
172
|
- lib/qme/randomizer/patient_randomization_job.rb
|
179
173
|
- lib/qme/randomizer/patient_randomizer.rb
|
174
|
+
- lib/qme/randomizer/random_patient_creator.rb
|
180
175
|
- lib/qme_test.rb
|
181
176
|
- lib/quality-measure-engine.rb
|
182
177
|
- lib/tasks/fixtures.rake
|
@@ -192,30 +187,27 @@ files:
|
|
192
187
|
has_rdoc: true
|
193
188
|
homepage: http://github.com/pophealth/quality-measure-engine
|
194
189
|
licenses: []
|
195
|
-
|
196
190
|
post_install_message:
|
197
191
|
rdoc_options: []
|
198
|
-
|
199
|
-
require_paths:
|
192
|
+
require_paths:
|
200
193
|
- lib
|
201
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
194
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
202
195
|
none: false
|
203
|
-
requirements:
|
204
|
-
- -
|
205
|
-
- !ruby/object:Gem::Version
|
206
|
-
version:
|
207
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - ! '>='
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
201
|
none: false
|
209
|
-
requirements:
|
210
|
-
- -
|
211
|
-
- !ruby/object:Gem::Version
|
212
|
-
version:
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
213
206
|
requirements: []
|
214
|
-
|
215
207
|
rubyforge_project:
|
216
208
|
rubygems_version: 1.6.2
|
217
209
|
signing_key:
|
218
210
|
specification_version: 3
|
219
|
-
summary: A library for extracting quality measure information from HITSP C32's and
|
211
|
+
summary: A library for extracting quality measure information from HITSP C32's and
|
212
|
+
ASTM CCR's
|
220
213
|
test_files: []
|
221
|
-
|
data/lib/qme/ext/string.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module QME
|
2
|
-
module Importer
|
3
|
-
# General helpers for working with codes and code systems
|
4
|
-
class CodeSystemHelper
|
5
|
-
CODE_SYSTEMS = {
|
6
|
-
'2.16.840.1.113883.6.1' => 'LOINC',
|
7
|
-
'2.16.840.1.113883.6.96' => 'SNOMED-CT',
|
8
|
-
'2.16.840.1.113883.6.12' => 'CPT',
|
9
|
-
#'2.16.840.1.113883.3.88.12.80.32' => 'CPT',
|
10
|
-
'2.16.840.1.113883.6.88' => 'RxNorm',
|
11
|
-
'2.16.840.1.113883.6.103' => 'ICD-9-CM',
|
12
|
-
'2.16.840.1.113883.6.104' => 'ICD-9-CM',
|
13
|
-
'2.16.840.1.113883.6.90' => 'ICD-10-CM',
|
14
|
-
'2.16.840.1.113883.6.14' => 'HCPCS',
|
15
|
-
'2.16.840.1.113883.6.59' => 'CVX',
|
16
|
-
'2.16.840.1.113883.6.238' => 'CDC-RE'
|
17
|
-
}
|
18
|
-
|
19
|
-
# Returns the name of a code system given an oid
|
20
|
-
# @param [String] oid of a code system
|
21
|
-
# @return [String] the name of the code system as described in the measure definition JSON
|
22
|
-
def self.code_system_for(oid)
|
23
|
-
CODE_SYSTEMS[oid] || "Unknown"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns the oid for a code system given a codesystem name
|
27
|
-
# @param [String] the name of the code system
|
28
|
-
# @return [String] the oid of the code system
|
29
|
-
def self.oid_for_code_system(code_system)
|
30
|
-
CODE_SYSTEMS.invert[code_system]
|
31
|
-
end
|
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
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module QME
|
2
|
-
module Importer
|
3
|
-
|
4
|
-
# General helpers for working with HL7 data types
|
5
|
-
class HL7Helper
|
6
|
-
|
7
|
-
# Converts an HL7 timestamp into an Integer
|
8
|
-
# @param [String] timestamp the HL7 timestamp. Expects YYYYMMDD format
|
9
|
-
# @return [Integer] Date in seconds since the epoch
|
10
|
-
def self.timestamp_to_integer(timestamp)
|
11
|
-
if timestamp && timestamp.length >= 4
|
12
|
-
year = timestamp[0..3].to_i
|
13
|
-
month = timestamp.length >= 6 ? timestamp[4..5].to_i : 1
|
14
|
-
day = timestamp.length >= 8 ? timestamp[6..7].to_i : 1
|
15
|
-
hour = timestamp.length >= 10 ? timestamp[8..9].to_i : 0
|
16
|
-
min = timestamp.length >= 12 ? timestamp[10..11].to_i : 0
|
17
|
-
sec = timestamp.length >= 14 ? timestamp[12..13].to_i : 0
|
18
|
-
|
19
|
-
Time.gm(year, month, day, hour, min, sec).to_i
|
20
|
-
else
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,228 +0,0 @@
|
|
1
|
-
module QME
|
2
|
-
module Importer
|
3
|
-
|
4
|
-
# This class is the central location for taking a HITSP C32 XML document and converting it
|
5
|
-
# into the processed form we store in MongoDB. The class does this by running each measure
|
6
|
-
# independently on the XML document
|
7
|
-
#
|
8
|
-
# This class is a Singleton. It should be accessed by calling PatientImporter.instance
|
9
|
-
class PatientImporter
|
10
|
-
|
11
|
-
include Singleton
|
12
|
-
|
13
|
-
# Creates a new PatientImporter with the following XPath expressions used to find content in
|
14
|
-
# a HITSP C32:
|
15
|
-
#
|
16
|
-
# Encounter entries
|
17
|
-
# //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter
|
18
|
-
#
|
19
|
-
# Procedure entries
|
20
|
-
# //cda:procedure[cda:templateId/@root='2.16.840.1.113883.10.20.1.29']
|
21
|
-
#
|
22
|
-
# Result entries - There seems to be some confusion around the correct templateId, so the code checks for both
|
23
|
-
# //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15.1'] | //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15']
|
24
|
-
#
|
25
|
-
# Vital sign entries
|
26
|
-
# //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.14']
|
27
|
-
#
|
28
|
-
# Medication entries
|
29
|
-
# //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration
|
30
|
-
#
|
31
|
-
# Codes for medications are found in the substanceAdministration with the following relative XPath
|
32
|
-
# ./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code
|
33
|
-
#
|
34
|
-
# Condition entries
|
35
|
-
# //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation
|
36
|
-
#
|
37
|
-
# Codes for conditions are determined by examining the value child element as opposed to the code child element
|
38
|
-
#
|
39
|
-
# Social History entries (non-C32 section, specified in the HL7 CCD)
|
40
|
-
# //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']
|
41
|
-
#
|
42
|
-
# Care Goal entries(non-C32 section, specified in the HL7 CCD)
|
43
|
-
# //cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']
|
44
|
-
#
|
45
|
-
# Allergy entries
|
46
|
-
# //cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']
|
47
|
-
#
|
48
|
-
# Immunization entries
|
49
|
-
# //cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.1.24']
|
50
|
-
#
|
51
|
-
# Codes for immunizations are found in the substanceAdministration with the following relative XPath
|
52
|
-
# ./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code
|
53
|
-
def initialize (check_usable = true)
|
54
|
-
@measure_importers = {}
|
55
|
-
@section_importers = {}
|
56
|
-
@id_map = {}
|
57
|
-
@section_importers[:encounters] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter")
|
58
|
-
@section_importers[:procedures] = SectionImporter.new("//cda:procedure[cda:templateId/@root='2.16.840.1.113883.10.20.1.29']")
|
59
|
-
@section_importers[:results] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15.1'] | //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15']")
|
60
|
-
@section_importers[:vital_signs] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.14']")
|
61
|
-
@section_importers[:medications] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration",
|
62
|
-
"./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code",
|
63
|
-
nil,
|
64
|
-
"./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]")
|
65
|
-
@section_importers[:conditions] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation",
|
66
|
-
"./cda:value",
|
67
|
-
"./cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.50']/cda:value",
|
68
|
-
"./cda:text/cda:reference[@value]")
|
69
|
-
@section_importers[:social_history] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']")
|
70
|
-
@section_importers[:care_goals] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']")
|
71
|
-
@section_importers[:medical_equipment] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.128']/cda:entry/cda:supply",
|
72
|
-
"./cda:participant/cda:participantRole/cda:playingDevice/cda:code")
|
73
|
-
@section_importers[:allergies] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']",
|
74
|
-
"./cda:participant/cda:participantRole/cda:playingEntity/cda:code")
|
75
|
-
@section_importers[:immunizations] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.117']/cda:entry/cda:substanceAdministration",
|
76
|
-
"./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code",
|
77
|
-
nil,
|
78
|
-
"./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]" )
|
79
|
-
end
|
80
|
-
|
81
|
-
def build_id_map(doc)
|
82
|
-
id_map = {}
|
83
|
-
path = "//*[@ID]"
|
84
|
-
ids = doc.xpath(path)
|
85
|
-
ids.each do |id|
|
86
|
-
tag = id['ID']
|
87
|
-
value = id.content
|
88
|
-
id_map[tag] = value
|
89
|
-
end
|
90
|
-
return id_map
|
91
|
-
end
|
92
|
-
|
93
|
-
# @param [boolean] value for check_usable_entries...importer uses true, stats uses false
|
94
|
-
def check_usable(check_usable_entries)
|
95
|
-
@section_importers.each_pair do |section, importer|
|
96
|
-
importer.check_for_usable = check_usable_entries
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Parses a HITSP C32 document and returns a Hash of of the patient.
|
101
|
-
#
|
102
|
-
# @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
|
103
|
-
# will have the "cda" namespace registered to "urn:hl7-org:v3"
|
104
|
-
# @return [Hash] a representation of the patient that can be inserted into MongoDB
|
105
|
-
def parse_c32(doc)
|
106
|
-
c32_patient = {}
|
107
|
-
entries = create_c32_hash(doc)
|
108
|
-
get_demographics(c32_patient, doc)
|
109
|
-
process_events(c32_patient, entries)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Parses a patient hash containing demographic and event information
|
113
|
-
#
|
114
|
-
# @param [Hash] patient_hash patient data
|
115
|
-
# @return [Hash] a representation of the patient that can be inserted into MongoDB
|
116
|
-
def parse_hash(patient_hash)
|
117
|
-
patient_record = {}
|
118
|
-
patient_record['first'] = patient_hash['first']
|
119
|
-
patient_record['patient_id'] = patient_hash['patient_id']
|
120
|
-
patient_record['last'] = patient_hash['last']
|
121
|
-
patient_record['gender'] = patient_hash['gender']
|
122
|
-
patient_record['patient_id'] = patient_hash['patient_id']
|
123
|
-
patient_record['birthdate'] = patient_hash['birthdate']
|
124
|
-
patient_record['race'] = patient_hash['race']
|
125
|
-
patient_record['ethnicity'] = patient_hash['ethnicity']
|
126
|
-
patient_record['languages'] = patient_hash['languages']
|
127
|
-
patient_record['addresses'] = patient_hash['addresses']
|
128
|
-
event_hash = {}
|
129
|
-
patient_hash['events'].each do |key, value|
|
130
|
-
event_hash[key.intern] = parse_events(value)
|
131
|
-
end
|
132
|
-
process_events(patient_record, event_hash)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Adds the entries and denormalized measure information to the patient_record.
|
136
|
-
# Each Entry will be converted to a Hash and stored in an Array under the appropriate
|
137
|
-
# section key, such as medications. Measure information is listed under the measures
|
138
|
-
# key which has a Hash value. The Hash has the measure id as a key, and the denormalized
|
139
|
-
# measure information as a value
|
140
|
-
#
|
141
|
-
# @param patient_record - Hash with basic patient demographic information
|
142
|
-
# @entries - Hash of entries with section names a keys and an Array of Entry values
|
143
|
-
def process_events(patient_record, entries)
|
144
|
-
patient_record['measures'] = {}
|
145
|
-
@measure_importers.each_pair do |measure_id, importer|
|
146
|
-
patient_record['measures'][measure_id] = importer.parse(entries)
|
147
|
-
end
|
148
|
-
|
149
|
-
entries.each_pair do |key, value|
|
150
|
-
patient_record[key] = value.map do |e|
|
151
|
-
if e.usable?
|
152
|
-
e.to_hash
|
153
|
-
else
|
154
|
-
nil
|
155
|
-
end
|
156
|
-
end.compact
|
157
|
-
end
|
158
|
-
|
159
|
-
patient_record
|
160
|
-
end
|
161
|
-
|
162
|
-
# Parses a list of event hashes into an array of Entry objects
|
163
|
-
#
|
164
|
-
# @param [Array] event_list list of event hashes
|
165
|
-
# @return [Array] array of Entry objects
|
166
|
-
def parse_events(event_list)
|
167
|
-
event_list.collect do |event|
|
168
|
-
if event.class==String.class
|
169
|
-
# skip String elements in the event list, patient randomization templates
|
170
|
-
# introduce String elements to simplify tailing-comma handling when generating
|
171
|
-
# JSON using ERb
|
172
|
-
nil
|
173
|
-
else
|
174
|
-
QME::Importer::Entry.from_event_hash(event)
|
175
|
-
end
|
176
|
-
end.compact
|
177
|
-
end
|
178
|
-
|
179
|
-
# Adds a measure to run on a C32 that is passed in
|
180
|
-
#
|
181
|
-
# @param [MeasureBase] measure an Class that can extract information from a C32 that is necessary
|
182
|
-
# to calculate the measure
|
183
|
-
def add_measure(measure_id, importer)
|
184
|
-
@measure_importers[measure_id] = importer
|
185
|
-
end
|
186
|
-
|
187
|
-
# Create a simple representation of the patient from a HITSP C32
|
188
|
-
#
|
189
|
-
# @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
|
190
|
-
# will have the "cda" namespace registered to "urn:hl7-org:v3"
|
191
|
-
# @return [Hash] a represnetation of the patient with symbols as keys for each section
|
192
|
-
def create_c32_hash(doc, check_usable_entries = true)
|
193
|
-
c32_patient = {}
|
194
|
-
id_map = build_id_map(doc)
|
195
|
-
@section_importers.each_pair do |section, importer|
|
196
|
-
importer.check_for_usable = check_usable_entries
|
197
|
-
c32_patient[section] = importer.create_entries(doc,id_map)
|
198
|
-
end
|
199
|
-
c32_patient
|
200
|
-
end
|
201
|
-
|
202
|
-
# Inspects a C32 document and populates the patient Hash with first name, last name
|
203
|
-
# birth date and gender.
|
204
|
-
#
|
205
|
-
# @param [Hash] patient A hash that is used to represent the patient
|
206
|
-
# @param [Nokogiri::XML::Node] doc The C32 document parsed by Nokogiri
|
207
|
-
def get_demographics(patient, doc)
|
208
|
-
patient['first'] = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:name/cda:given').text
|
209
|
-
patient['last'] = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:name/cda:family').text
|
210
|
-
birthdate_in_hl7ts_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:birthTime')
|
211
|
-
birthdate_in_hl7ts = birthdate_in_hl7ts_node['value']
|
212
|
-
patient['birthdate'] = HL7Helper.timestamp_to_integer(birthdate_in_hl7ts)
|
213
|
-
gender_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:administrativeGenderCode')
|
214
|
-
patient['gender'] = gender_node['code']
|
215
|
-
race_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:raceCode')
|
216
|
-
patient['race'] = race_node['code'] if race_node
|
217
|
-
ethnicity_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:ethnicGroupCode')
|
218
|
-
patient['ethnicity'] = ethnicity_node['code'] if ethnicity_node
|
219
|
-
|
220
|
-
languages = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient').search('languageCommunication').map {|lc| lc.at_xpath('cda:languageCode')['code'] }
|
221
|
-
patient['languages'] = languages unless languages.empty?
|
222
|
-
|
223
|
-
id_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:id')
|
224
|
-
patient['patient_id'] = id_node['extension']
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|