hqmf2js 1.0.1 → 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 +5 -10
- data/Gemfile.lock +70 -68
- data/app/assets/javascripts/custom_calculations.js.coffee +72 -0
- data/app/assets/javascripts/hqmf_util.js.coffee +97 -46
- data/app/assets/javascripts/logging_utils.js.coffee +0 -11
- data/app/assets/javascripts/specifics.js.coffee +211 -185
- data/app/assets/javascripts/underscore.js +1200 -0
- data/hqmf2js.gemspec +5 -5
- data/lib/generator/characteristic.js.erb +3 -3
- data/lib/generator/converter.rb +5 -5
- data/lib/generator/data_criteria.js.erb +8 -8
- data/lib/generator/js.rb +25 -5
- data/test/fixtures/codes/codes.xml +6 -0
- data/test/fixtures/patients/larry_vanderman.json +11 -1
- data/test/test_helper.rb +2 -3
- data/test/unit/codes_to_json_test.rb +1 -1
- data/test/unit/custom_calculations_test.rb +74 -0
- data/test/unit/hqmf_from_json_javascript_test.rb +9 -9
- data/test/unit/hqmf_javascript_test.rb +36 -14
- data/test/unit/library_function_test.rb +29 -11
- data/test/unit/specifics_test.rb +200 -82
- metadata +13 -9
- data/test/fixtures/patient_api.js +0 -2823
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem 'rails'
|
3
|
+
gem 'rails', '3.2.9'
|
4
4
|
|
5
5
|
group :assets do
|
6
6
|
gem 'sass-rails'
|
@@ -8,17 +8,12 @@ group :assets do
|
|
8
8
|
gem 'uglifier'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
gem
|
14
|
-
#gem 'hqmf-parser', :git => 'https://github.com/pophealth/hqmf-parser.git', :branch => 'develop'
|
15
|
-
#gem 'hqmf-parser', :path => '../hqmf-parser'
|
16
|
-
gem 'hqmf-parser', '~> 1.0.4'
|
17
|
-
#gem "health-data-standards", :git => 'http://github.com/projectcypress/health-data-standards.git', :branch => 'develop'
|
18
|
-
gem "health-data-standards", '~> 2.1.3'
|
11
|
+
gem "hquery-patient-api", '~> 1.0.0'
|
12
|
+
gem 'hqmf-parser', '~> 1.1.0'
|
13
|
+
gem "health-data-standards", '~> 2.2.0'
|
19
14
|
|
20
15
|
gem 'nokogiri'
|
21
|
-
gem 'sprockets'
|
16
|
+
gem 'sprockets', '~> 2.2.2'
|
22
17
|
gem 'coffee-script'
|
23
18
|
gem 'uglifier'
|
24
19
|
gem 'tilt'
|
data/Gemfile.lock
CHANGED
@@ -1,53 +1,53 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
actionmailer (3.2.
|
5
|
-
actionpack (= 3.2.
|
4
|
+
actionmailer (3.2.9)
|
5
|
+
actionpack (= 3.2.9)
|
6
6
|
mail (~> 2.4.4)
|
7
|
-
actionpack (3.2.
|
8
|
-
activemodel (= 3.2.
|
9
|
-
activesupport (= 3.2.
|
7
|
+
actionpack (3.2.9)
|
8
|
+
activemodel (= 3.2.9)
|
9
|
+
activesupport (= 3.2.9)
|
10
10
|
builder (~> 3.0.0)
|
11
11
|
erubis (~> 2.7.0)
|
12
|
-
journey (~> 1.0.
|
12
|
+
journey (~> 1.0.4)
|
13
13
|
rack (~> 1.4.0)
|
14
14
|
rack-cache (~> 1.2)
|
15
15
|
rack-test (~> 0.6.1)
|
16
|
-
sprockets (~> 2.1
|
17
|
-
activemodel (3.2.
|
18
|
-
activesupport (= 3.2.
|
16
|
+
sprockets (~> 2.2.1)
|
17
|
+
activemodel (3.2.9)
|
18
|
+
activesupport (= 3.2.9)
|
19
19
|
builder (~> 3.0.0)
|
20
|
-
activerecord (3.2.
|
21
|
-
activemodel (= 3.2.
|
22
|
-
activesupport (= 3.2.
|
20
|
+
activerecord (3.2.9)
|
21
|
+
activemodel (= 3.2.9)
|
22
|
+
activesupport (= 3.2.9)
|
23
23
|
arel (~> 3.0.2)
|
24
24
|
tzinfo (~> 0.3.29)
|
25
|
-
activeresource (3.2.
|
26
|
-
activemodel (= 3.2.
|
27
|
-
activesupport (= 3.2.
|
28
|
-
activesupport (3.2.
|
25
|
+
activeresource (3.2.9)
|
26
|
+
activemodel (= 3.2.9)
|
27
|
+
activesupport (= 3.2.9)
|
28
|
+
activesupport (3.2.9)
|
29
29
|
i18n (~> 0.6)
|
30
30
|
multi_json (~> 1.0)
|
31
|
-
ansi (1.4.
|
31
|
+
ansi (1.4.3)
|
32
32
|
arel (3.0.2)
|
33
|
-
awesome_print (1.0
|
34
|
-
builder (3.0.
|
33
|
+
awesome_print (1.1.0)
|
34
|
+
builder (3.0.4)
|
35
35
|
choice (0.1.6)
|
36
|
-
coderay (1.0.
|
36
|
+
coderay (1.0.8)
|
37
37
|
coffee-rails (3.2.2)
|
38
38
|
coffee-script (>= 2.2.0)
|
39
39
|
railties (~> 3.2.0)
|
40
40
|
coffee-script (2.2.0)
|
41
41
|
coffee-script-source
|
42
42
|
execjs
|
43
|
-
coffee-script-source (1.
|
43
|
+
coffee-script-source (1.4.0)
|
44
44
|
configatron (2.9.1)
|
45
45
|
yamler (>= 0.1.0)
|
46
46
|
cover_me (1.2.0)
|
47
47
|
configatron
|
48
48
|
hashie
|
49
49
|
erubis (2.7.0)
|
50
|
-
execjs (1.
|
50
|
+
execjs (1.4.0)
|
51
51
|
multi_json (~> 1.0)
|
52
52
|
faraday (0.8.4)
|
53
53
|
multipart-post (~> 1.1)
|
@@ -56,24 +56,25 @@ GEM
|
|
56
56
|
oauth (>= 0.3.6)
|
57
57
|
oauth2 (>= 0.5.0)
|
58
58
|
hashie (1.2.0)
|
59
|
-
health-data-standards (2.
|
59
|
+
health-data-standards (2.2.0)
|
60
|
+
activesupport (~> 3.2.9)
|
60
61
|
builder (~> 3.0.0)
|
61
62
|
erubis (~> 2.7.0)
|
62
|
-
mongoid (~> 3.0.
|
63
|
+
mongoid (~> 3.0.14)
|
63
64
|
nokogiri (~> 1.5.5)
|
64
65
|
rest-client (~> 1.6.7)
|
65
66
|
uuid (~> 2.3.5)
|
66
67
|
hike (1.2.1)
|
67
|
-
hqmf-parser (1.0
|
68
|
+
hqmf-parser (1.1.0)
|
68
69
|
google-spreadsheet-ruby (= 0.1.8)
|
69
70
|
roo (= 1.10.1)
|
70
71
|
rubyzip
|
71
72
|
spreadsheet (= 0.6.8)
|
72
|
-
hquery-patient-api (0.
|
73
|
+
hquery-patient-api (1.0.0)
|
73
74
|
httpauth (0.2.0)
|
74
75
|
i18n (0.6.1)
|
75
|
-
journey (1.0.
|
76
|
-
json (1.7.
|
76
|
+
journey (1.0.4)
|
77
|
+
json (1.7.5)
|
77
78
|
jwt (0.1.5)
|
78
79
|
multi_json (>= 1.0)
|
79
80
|
libv8 (3.3.10.4)
|
@@ -84,16 +85,16 @@ GEM
|
|
84
85
|
i18n (>= 0.4.0)
|
85
86
|
mime-types (~> 1.16)
|
86
87
|
treetop (~> 1.4.8)
|
87
|
-
method_source (0.
|
88
|
-
mime-types (1.
|
89
|
-
minitest (
|
90
|
-
mongoid (3.0.
|
88
|
+
method_source (0.8.1)
|
89
|
+
mime-types (1.19)
|
90
|
+
minitest (4.3.2)
|
91
|
+
mongoid (3.0.15)
|
91
92
|
activemodel (~> 3.1)
|
92
93
|
moped (~> 1.1)
|
93
94
|
origin (~> 1.0)
|
94
95
|
tzinfo (~> 0.3.22)
|
95
|
-
moped (1.
|
96
|
-
multi_json (1.
|
96
|
+
moped (1.3.1)
|
97
|
+
multi_json (1.4.0)
|
97
98
|
multipart-post (1.1.5)
|
98
99
|
nokogiri (1.5.5)
|
99
100
|
oauth (0.4.7)
|
@@ -103,35 +104,35 @@ GEM
|
|
103
104
|
jwt (~> 0.1.4)
|
104
105
|
multi_json (~> 1.0)
|
105
106
|
rack (~> 1.2)
|
106
|
-
origin (1.0.
|
107
|
+
origin (1.0.11)
|
107
108
|
polyglot (0.3.3)
|
108
|
-
pry (0.9.
|
109
|
+
pry (0.9.10)
|
109
110
|
coderay (~> 1.0.5)
|
110
|
-
method_source (~> 0.
|
111
|
-
slop (
|
111
|
+
method_source (~> 0.8)
|
112
|
+
slop (~> 3.3.1)
|
112
113
|
rack (1.4.1)
|
113
114
|
rack-cache (1.2)
|
114
115
|
rack (>= 0.4)
|
115
116
|
rack-ssl (1.3.2)
|
116
117
|
rack
|
117
|
-
rack-test (0.6.
|
118
|
+
rack-test (0.6.2)
|
118
119
|
rack (>= 1.0)
|
119
|
-
rails (3.2.
|
120
|
-
actionmailer (= 3.2.
|
121
|
-
actionpack (= 3.2.
|
122
|
-
activerecord (= 3.2.
|
123
|
-
activeresource (= 3.2.
|
124
|
-
activesupport (= 3.2.
|
120
|
+
rails (3.2.9)
|
121
|
+
actionmailer (= 3.2.9)
|
122
|
+
actionpack (= 3.2.9)
|
123
|
+
activerecord (= 3.2.9)
|
124
|
+
activeresource (= 3.2.9)
|
125
|
+
activesupport (= 3.2.9)
|
125
126
|
bundler (~> 1.0)
|
126
|
-
railties (= 3.2.
|
127
|
-
railties (3.2.
|
128
|
-
actionpack (= 3.2.
|
129
|
-
activesupport (= 3.2.
|
127
|
+
railties (= 3.2.9)
|
128
|
+
railties (3.2.9)
|
129
|
+
actionpack (= 3.2.9)
|
130
|
+
activesupport (= 3.2.9)
|
130
131
|
rack-ssl (~> 1.3.2)
|
131
132
|
rake (>= 0.8.7)
|
132
133
|
rdoc (~> 3.4)
|
133
|
-
thor (
|
134
|
-
rake (0.
|
134
|
+
thor (>= 0.14.6, < 2.0)
|
135
|
+
rake (10.0.2)
|
135
136
|
rdoc (3.12)
|
136
137
|
json (~> 1.4)
|
137
138
|
rest-client (1.6.7)
|
@@ -143,37 +144,38 @@ GEM
|
|
143
144
|
rubyzip (>= 0.9.4)
|
144
145
|
spreadsheet (> 0.6.4)
|
145
146
|
todonotes (>= 0.1.0)
|
146
|
-
ruby-ole (1.2.11.
|
147
|
+
ruby-ole (1.2.11.6)
|
147
148
|
rubyzip (0.9.9)
|
148
|
-
sass (3.
|
149
|
+
sass (3.2.3)
|
149
150
|
sass-rails (3.2.5)
|
150
151
|
railties (~> 3.2.0)
|
151
152
|
sass (>= 3.1.10)
|
152
153
|
tilt (~> 1.3)
|
153
|
-
slop (
|
154
|
+
slop (3.3.3)
|
154
155
|
spreadsheet (0.6.8)
|
155
156
|
ruby-ole (>= 1.0)
|
156
|
-
sprockets (2.
|
157
|
+
sprockets (2.2.2)
|
157
158
|
hike (~> 1.2)
|
159
|
+
multi_json (~> 1.0)
|
158
160
|
rack (~> 1.0)
|
159
161
|
tilt (~> 1.1, != 1.3.0)
|
160
162
|
systemu (2.5.2)
|
161
163
|
therubyracer (0.10.2)
|
162
164
|
libv8 (~> 3.3.10)
|
163
|
-
thor (0.
|
165
|
+
thor (0.16.0)
|
164
166
|
tilt (1.3.3)
|
165
|
-
todonotes (0.1.
|
167
|
+
todonotes (0.1.1)
|
166
168
|
log4r
|
167
|
-
treetop (1.4.
|
169
|
+
treetop (1.4.12)
|
168
170
|
polyglot
|
169
171
|
polyglot (>= 0.3.1)
|
170
|
-
turn (0.9.
|
172
|
+
turn (0.9.6)
|
171
173
|
ansi
|
172
|
-
tzinfo (0.3.
|
173
|
-
uglifier (1.
|
174
|
+
tzinfo (0.3.35)
|
175
|
+
uglifier (1.3.0)
|
174
176
|
execjs (>= 0.3.0)
|
175
|
-
multi_json (>= 1.0.2)
|
176
|
-
uuid (2.3.
|
177
|
+
multi_json (~> 1.0, >= 1.0.2)
|
178
|
+
uuid (2.3.6)
|
177
179
|
macaddr (~> 1.0)
|
178
180
|
yamler (0.1.0)
|
179
181
|
|
@@ -185,16 +187,16 @@ DEPENDENCIES
|
|
185
187
|
coffee-rails
|
186
188
|
coffee-script
|
187
189
|
cover_me (~> 1.2.0)
|
188
|
-
health-data-standards (~> 2.
|
189
|
-
hqmf-parser (~> 1.0
|
190
|
-
hquery-patient-api (~> 0.
|
190
|
+
health-data-standards (~> 2.2.0)
|
191
|
+
hqmf-parser (~> 1.1.0)
|
192
|
+
hquery-patient-api (~> 1.0.0)
|
191
193
|
minitest
|
192
194
|
nokogiri
|
193
195
|
pry
|
194
|
-
rails
|
196
|
+
rails (= 3.2.9)
|
195
197
|
rake
|
196
198
|
sass-rails
|
197
|
-
sprockets
|
199
|
+
sprockets (~> 2.2.2)
|
198
200
|
therubyracer
|
199
201
|
therubyrhino
|
200
202
|
tilt
|
@@ -0,0 +1,72 @@
|
|
1
|
+
@hqmf.CustomCalc = {}
|
2
|
+
|
3
|
+
class @hqmf.CustomCalc.PercentTTREntries extends hQuery.CodedEntryList
|
4
|
+
|
5
|
+
constructor: (events) ->
|
6
|
+
super()
|
7
|
+
events = events.sort(dateSortAscending)
|
8
|
+
@push(event) for event in events
|
9
|
+
@minInr = 2.0
|
10
|
+
@maxInr = 3.0
|
11
|
+
# sort entries ascending
|
12
|
+
# filter duplicates to those closest to 2.5
|
13
|
+
# remove duplicate results on entries
|
14
|
+
|
15
|
+
calculateDaysInRange: (firstInr, secondInr) ->
|
16
|
+
|
17
|
+
if ((@belowRange(firstInr) and @belowRange(secondInr)) or (@aboveRange(firstInr) and @aboveRange(secondInr)))
|
18
|
+
0
|
19
|
+
else if (@inRange(firstInr) and @inRange(secondInr))
|
20
|
+
@differenceInDays(firstInr,secondInr)
|
21
|
+
else if (@outsideRange(firstInr) and @inRange(secondInr))
|
22
|
+
@calculateCrossingRange(firstInr,secondInr)
|
23
|
+
else if (@inRange(firstInr) and @outsideRange(secondInr))
|
24
|
+
@calculateCrossingRange(secondInr, firstInr)
|
25
|
+
else
|
26
|
+
@calculateSpanningRange(firstInr, secondInr)
|
27
|
+
|
28
|
+
calculateCrossingRange: (outside,inside) ->
|
29
|
+
outsideInr = @inrValue(outside)
|
30
|
+
insideInr = @inrValue(inside)
|
31
|
+
boundary = @maxInr
|
32
|
+
boundary = @minInr if (@belowRange(outside))
|
33
|
+
(Math.abs(boundary - insideInr)/Math.abs(insideInr-outsideInr))*@differenceInDays(outside,inside)
|
34
|
+
|
35
|
+
calculateSpanningRange: (first,second) ->
|
36
|
+
(1.0/Math.abs(@inrValue(first)-@inrValue(second)))*@differenceInDays(first,second)
|
37
|
+
|
38
|
+
inRange: (entry) ->
|
39
|
+
inr = @inrValue(entry)
|
40
|
+
inr >= @minInr and inr <= @maxInr
|
41
|
+
|
42
|
+
outsideRange: (entry) ->
|
43
|
+
!@inRange(entry)
|
44
|
+
|
45
|
+
belowRange: (entry) ->
|
46
|
+
inr = @inrValue(entry)
|
47
|
+
inr < @minInr
|
48
|
+
|
49
|
+
aboveRange: (entry) ->
|
50
|
+
inr = @inrValue(entry)
|
51
|
+
inr > @maxInr
|
52
|
+
|
53
|
+
differenceInDays: (first, second) ->
|
54
|
+
getIVL(first).low.difference(getIVL(second).low, 'd')
|
55
|
+
|
56
|
+
inrValue: (entry) ->
|
57
|
+
entry.values()[0].scalar()
|
58
|
+
|
59
|
+
totalNumberOfDays: () ->
|
60
|
+
@differenceInDays(this[0],this[this.length-1])
|
61
|
+
|
62
|
+
calculateTTR: () ->
|
63
|
+
total = 0
|
64
|
+
for left, i in this
|
65
|
+
if (i < this.length-1)
|
66
|
+
right = this[i+1]
|
67
|
+
total += @calculateDaysInRange(left, right)
|
68
|
+
total
|
69
|
+
|
70
|
+
calculatePercentTTR: () ->
|
71
|
+
@calculateTTR()/@totalNumberOfDays()*100
|
72
|
+
|
@@ -15,7 +15,7 @@ class TS
|
|
15
15
|
minute = parseInt(hl7ts.substring(10,12), 10)
|
16
16
|
if isNaN(minute)
|
17
17
|
minute = 0
|
18
|
-
@date = new Date(year, month, day, hour, minute)
|
18
|
+
@date = new Date(Date.UTC(year, month, day, hour, minute))
|
19
19
|
else
|
20
20
|
@date = new Date()
|
21
21
|
|
@@ -24,17 +24,17 @@ class TS
|
|
24
24
|
# wk (week), d (day), h (hour) and min (minute).
|
25
25
|
add: (pq) ->
|
26
26
|
if pq.unit=="a"
|
27
|
-
@date.
|
27
|
+
@date.setUTCFullYear(@date.getUTCFullYear()+pq.value)
|
28
28
|
else if pq.unit=="mo"
|
29
|
-
@date.
|
29
|
+
@date.setUTCMonth(@date.getUTCMonth()+pq.value)
|
30
30
|
else if pq.unit=="wk"
|
31
|
-
@date.
|
31
|
+
@date.setUTCDate(@date.getUTCDate()+(7*pq.value))
|
32
32
|
else if pq.unit=="d"
|
33
|
-
@date.
|
33
|
+
@date.setUTCDate(@date.getUTCDate()+pq.value)
|
34
34
|
else if pq.unit=="h"
|
35
|
-
@date.
|
35
|
+
@date.setUTCHours(@date.getUTCHours()+pq.value)
|
36
36
|
else if pq.unit=="min"
|
37
|
-
@date.
|
37
|
+
@date.setUTCMinutes(@date.getUTCMinutes()+pq.value)
|
38
38
|
else
|
39
39
|
throw "Unknown time unit: "+pq.unit
|
40
40
|
this
|
@@ -76,7 +76,7 @@ class TS
|
|
76
76
|
if @date==null || other.date==null
|
77
77
|
return false
|
78
78
|
if other.inclusive
|
79
|
-
beforeOrConcurrent(other)
|
79
|
+
@beforeOrConcurrent(other)
|
80
80
|
else
|
81
81
|
[a,b] = TS.dropSeconds(@date, other.date)
|
82
82
|
a.getTime() < b.getTime()
|
@@ -86,7 +86,7 @@ class TS
|
|
86
86
|
if @date==null || other.date==null
|
87
87
|
return false
|
88
88
|
if other.inclusive
|
89
|
-
afterOrConcurrent(other)
|
89
|
+
@afterOrConcurrent(other)
|
90
90
|
else
|
91
91
|
[a,b] = TS.dropSeconds(@date, other.date)
|
92
92
|
a.getTime() > b.getTime()
|
@@ -113,21 +113,21 @@ class TS
|
|
113
113
|
|
114
114
|
# Number of whole years between the two time stamps (as Date objects)
|
115
115
|
@yearsDifference: (earlier, later) ->
|
116
|
-
if (later.
|
117
|
-
later.
|
118
|
-
else if (later.
|
119
|
-
later.
|
120
|
-
else if (later.
|
121
|
-
later.
|
116
|
+
if (later.getUTCMonth() < earlier.getUTCMonth())
|
117
|
+
later.getUTCFullYear()-earlier.getUTCFullYear()-1
|
118
|
+
else if (later.getUTCMonth() == earlier.getUTCMonth() && later.getUTCDate() >= earlier.getUTCDate())
|
119
|
+
later.getUTCFullYear()-earlier.getUTCFullYear()
|
120
|
+
else if (later.getUTCMonth() == earlier.getUTCMonth() && later.getUTCDate() < earlier.getUTCDate())
|
121
|
+
later.getUTCFullYear()-earlier.getUTCFullYear()-1
|
122
122
|
else
|
123
|
-
later.
|
123
|
+
later.getUTCFullYear()-earlier.getUTCFullYear()
|
124
124
|
|
125
125
|
# Number of whole months between the two time stamps (as Date objects)
|
126
126
|
@monthsDifference: (earlier, later) ->
|
127
|
-
if (later.
|
128
|
-
(later.
|
127
|
+
if (later.getUTCDate() >= earlier.getUTCDate())
|
128
|
+
(later.getUTCFullYear()-earlier.getUTCFullYear())*12+later.getUTCMonth()-earlier.getUTCMonth()
|
129
129
|
else
|
130
|
-
(later.
|
130
|
+
(later.getUTCFullYear()-earlier.getUTCFullYear())*12+later.getUTCMonth()-earlier.getUTCMonth()-1
|
131
131
|
|
132
132
|
# Number of whole minutes between the two time stamps (as Date objects)
|
133
133
|
@minutesDifference: (earlier, later) ->
|
@@ -140,10 +140,8 @@ class TS
|
|
140
140
|
# Number of days betweem the two time stamps (as Date objects)
|
141
141
|
@daysDifference: (earlier, later) ->
|
142
142
|
# have to discard time portion for day difference calculation purposes
|
143
|
-
e = new Date(earlier.
|
144
|
-
|
145
|
-
l = new Date(later.getFullYear(), later.getMonth(), later.getDate())
|
146
|
-
l.setUTCHours(0)
|
143
|
+
e = new Date(Date.UTC(earlier.getUTCFullYear(), earlier.getUTCMonth(), earlier.getUTCDate()))
|
144
|
+
l = new Date(Date.UTC(later.getUTCFullYear(), later.getUTCMonth(), later.getUTCDate()))
|
147
145
|
Math.floor(TS.hoursDifference(e,l)/24)
|
148
146
|
|
149
147
|
# Number of whole weeks between the two time stmaps (as Date objects)
|
@@ -413,25 +411,25 @@ class ANYNonNull
|
|
413
411
|
atLeastOneTrue = (values...) ->
|
414
412
|
trueValues = (value for value in values when value && value.isTrue())
|
415
413
|
trueValues.length>0
|
416
|
-
|
414
|
+
hqmf.SpecificsManager.unionAll(new Boolean(trueValues.length>0), values)
|
417
415
|
@atLeastOneTrue = atLeastOneTrue
|
418
416
|
|
419
417
|
# Returns true if all of the supplied values are true
|
420
418
|
allTrue = (values...) ->
|
421
419
|
trueValues = (value for value in values when value && value.isTrue())
|
422
|
-
|
420
|
+
hqmf.SpecificsManager.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
|
423
421
|
@allTrue = allTrue
|
424
422
|
|
425
423
|
# Returns true if one or more of the supplied values is false
|
426
424
|
atLeastOneFalse = (values...) ->
|
427
425
|
falseValues = (value for value in values when value.isFalse())
|
428
|
-
|
426
|
+
hqmf.SpecificsManager.intersectAll(new Boolean(falseValues.length>0), values, true)
|
429
427
|
@atLeastOneFalse = atLeastOneFalse
|
430
428
|
|
431
429
|
# Returns true if all of the supplied values are false
|
432
430
|
allFalse = (values...) ->
|
433
431
|
falseValues = (value for value in values when value.isFalse())
|
434
|
-
|
432
|
+
hqmf.SpecificsManager.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
|
435
433
|
@allFalse = allFalse
|
436
434
|
|
437
435
|
# Return true if compareTo matches value
|
@@ -454,12 +452,56 @@ filterEventsByValue = (events, value) ->
|
|
454
452
|
# Return only those events with a field that matches the supplied value
|
455
453
|
filterEventsByField = (events, field, value) ->
|
456
454
|
respondingEvents = (event for event in events when event.respondTo(field))
|
457
|
-
event for event in respondingEvents when value.match(event[field]())
|
455
|
+
result = (event for event in respondingEvents when value.match(event[field]()))
|
456
|
+
hqmf.SpecificsManager.maintainSpecifics(result, events)
|
458
457
|
@filterEventsByField = filterEventsByField
|
459
458
|
|
459
|
+
shiftTimes = (event, field) ->
|
460
|
+
shiftedEvent = new event.constructor(event.json)
|
461
|
+
shiftedEvent.setTimestamp(shiftedEvent[field]())
|
462
|
+
shiftedEvent
|
463
|
+
@shiftTimes = shiftTimes
|
464
|
+
|
465
|
+
adjustBoundsForField = (events, field) ->
|
466
|
+
validEvents = (event for event in events when (event.respondTo(field) and event[field]()))
|
467
|
+
shiftedEvents = (shiftTimes(event, field) for event in validEvents)
|
468
|
+
hqmf.SpecificsManager.maintainSpecifics(shiftedEvents, events)
|
469
|
+
@adjustBoundsForField = adjustBoundsForField
|
470
|
+
|
471
|
+
# Clone the supplied event and replace any facilities with just the supplied one
|
472
|
+
narrowEventForFacility = (event, facility) ->
|
473
|
+
narrowed = new event.constructor(event.json)
|
474
|
+
# uncomment the following line when patient API is modified to support multiple
|
475
|
+
# facilities
|
476
|
+
# narrowed._facilities = [facility]
|
477
|
+
narrowed
|
478
|
+
@narrowEventForFacility = narrowEventForFacility
|
479
|
+
|
480
|
+
# Return a cloned set of events, each with just one of the original facilities
|
481
|
+
denormalizeEvent = (event) ->
|
482
|
+
# the following line should be changed when the patient API is modified to support
|
483
|
+
# more than one facility per encounter
|
484
|
+
# narrowed = (narrowEventForFacility(event, facility) for facility in event.facilities)
|
485
|
+
narrowed = (narrowEventForFacility(event, facility) for facility in [event.facility])
|
486
|
+
@denormalizeEvent = denormalizeEvent
|
487
|
+
|
488
|
+
# Creates a new set of events with one location per event. Input events with more than
|
489
|
+
# one location will be duplicated once per location and each resulting event will
|
490
|
+
# be assigned one location. Start and end times of the event will be adjusted to match the
|
491
|
+
# value of the supplied field
|
492
|
+
denormalizeEventsByLocation = (events, field) ->
|
493
|
+
respondingEvents = (event for event in events when event.respondTo("facility") and event.facility())
|
494
|
+
denormalizedEvents = (denormalizeEvent(event) for event in respondingEvents)
|
495
|
+
denormalizedEvents = [].concat denormalizedEvents...
|
496
|
+
result = adjustBoundsForField(denormalizedEvents, field)
|
497
|
+
hqmf.SpecificsManager.maintainSpecifics(result, events)
|
498
|
+
@denormalizeEventsByLocation = denormalizeEventsByLocation
|
499
|
+
|
460
500
|
# Utility method to obtain the value set for an OID
|
461
501
|
getCodes = (oid) ->
|
462
|
-
OidDictionary[oid]
|
502
|
+
codes = OidDictionary[oid]
|
503
|
+
throw "value set oid could not be found: #{oid}" unless codes?
|
504
|
+
codes
|
463
505
|
@getCodes = getCodes
|
464
506
|
|
465
507
|
# Used for representing XPRODUCTs of arrays, holds both a flattened array that contains
|
@@ -475,7 +517,7 @@ class CrossProduct extends Array
|
|
475
517
|
|
476
518
|
# Create a CrossProduct of the supplied event lists.
|
477
519
|
XPRODUCT = (eventLists...) ->
|
478
|
-
|
520
|
+
hqmf.SpecificsManager.intersectAll(new CrossProduct(eventLists), eventLists)
|
479
521
|
@XPRODUCT = XPRODUCT
|
480
522
|
|
481
523
|
# Create a new list containing all the events from the supplied event lists
|
@@ -484,14 +526,14 @@ UNION = (eventLists...) ->
|
|
484
526
|
for eventList in eventLists
|
485
527
|
for event in eventList
|
486
528
|
union.push(event)
|
487
|
-
|
529
|
+
hqmf.SpecificsManager.unionAll(union, eventLists)
|
488
530
|
@UNION = UNION
|
489
531
|
|
490
532
|
# Return true if the number of events matches the supplied range
|
491
533
|
COUNT = (events, range) ->
|
492
534
|
count = events.length
|
493
535
|
result = new Boolean(range.match(count))
|
494
|
-
applySpecificOccurrenceSubset('COUNT',
|
536
|
+
applySpecificOccurrenceSubset('COUNT', hqmf.SpecificsManager.maintainSpecifics(result, events), range)
|
495
537
|
@COUNT = COUNT
|
496
538
|
|
497
539
|
# Convert an hQuery.CodedEntry or JS Date into an IVL_TS
|
@@ -521,7 +563,8 @@ eventAccessor = {
|
|
521
563
|
'SCW': 'low',
|
522
564
|
'ECWS': 'high'
|
523
565
|
'SCWE': 'low',
|
524
|
-
'CONCURRENT': 'low'
|
566
|
+
'CONCURRENT': 'low',
|
567
|
+
'DATEDIFF': 'low'
|
525
568
|
}
|
526
569
|
|
527
570
|
boundAccessor = {
|
@@ -541,7 +584,8 @@ boundAccessor = {
|
|
541
584
|
'SCW': 'low',
|
542
585
|
'ECWS': 'low'
|
543
586
|
'SCWE': 'high',
|
544
|
-
'CONCURRENT': 'low'
|
587
|
+
'CONCURRENT': 'low',
|
588
|
+
'DATEDIFF': 'low'
|
545
589
|
}
|
546
590
|
|
547
591
|
# Determine whether the supplied event falls within range of the supplied bound
|
@@ -563,7 +607,7 @@ eventMatchesBounds = (event, bounds, methodName, range) ->
|
|
563
607
|
currentMatches = eventMatchesBounds(event, boundList, methodName, range)
|
564
608
|
return [] if (currentMatches.length == 0)
|
565
609
|
matchingBounds = matchingBounds.concat(currentMatches)
|
566
|
-
return
|
610
|
+
return hqmf.SpecificsManager.maintainSpecifics(matchingBounds,bounds)
|
567
611
|
else
|
568
612
|
eventIVL = getIVL(event)
|
569
613
|
matchingBounds = (bound for bound in bounds when (
|
@@ -573,7 +617,7 @@ eventMatchesBounds = (event, bounds, methodName, range) ->
|
|
573
617
|
result &&= withinRange(methodName, eventIVL, boundIVL, range)
|
574
618
|
result
|
575
619
|
))
|
576
|
-
|
620
|
+
hqmf.SpecificsManager.maintainSpecifics(matchingBounds, bounds)
|
577
621
|
@eventMatchesBounds = eventMatchesBounds
|
578
622
|
|
579
623
|
# Determine which event match one of the supplied bounds
|
@@ -583,7 +627,7 @@ eventsMatchBounds = (events, bounds, methodName, range) ->
|
|
583
627
|
if (events.length==undefined)
|
584
628
|
events = [events]
|
585
629
|
|
586
|
-
specificContext = new
|
630
|
+
specificContext = new hqmf.SpecificOccurrence()
|
587
631
|
hasSpecificOccurrence = (events.specific_occurrence? || bounds.specific_occurrence?)
|
588
632
|
matchingEvents = []
|
589
633
|
matchingEvents.specific_occurrence = events.specific_occurrence
|
@@ -593,7 +637,7 @@ eventsMatchBounds = (events, bounds, methodName, range) ->
|
|
593
637
|
|
594
638
|
if hasSpecificOccurrence
|
595
639
|
matchingEvents.specific_occurrence = events.specific_occurrence
|
596
|
-
# TODO:
|
640
|
+
# TODO: well need a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
|
597
641
|
specificContext.addRows(Row.buildRowsForMatching(events.specific_occurrence, event, bounds.specific_occurrence, matchingBounds))
|
598
642
|
else
|
599
643
|
# add all stars
|
@@ -693,37 +737,37 @@ applySpecificOccurrenceSubset = (operator, result, range, calculateSpecifics) ->
|
|
693
737
|
FIRST = (events) ->
|
694
738
|
result = []
|
695
739
|
result = [events.sort(dateSortAscending)[0]] if (events.length > 0)
|
696
|
-
applySpecificOccurrenceSubset('FIRST',
|
740
|
+
applySpecificOccurrenceSubset('FIRST',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
697
741
|
@FIRST = FIRST
|
698
742
|
|
699
743
|
SECOND = (events) ->
|
700
744
|
result = []
|
701
745
|
result = [events.sort(dateSortAscending)[1]] if (events.length > 1)
|
702
|
-
applySpecificOccurrenceSubset('SECOND',
|
746
|
+
applySpecificOccurrenceSubset('SECOND',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
703
747
|
@SECOND = SECOND
|
704
748
|
|
705
749
|
THIRD = (events) ->
|
706
750
|
result = []
|
707
751
|
result = [events.sort(dateSortAscending)[2]] if (events.length > 2)
|
708
|
-
applySpecificOccurrenceSubset('THIRD',
|
752
|
+
applySpecificOccurrenceSubset('THIRD',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
709
753
|
@THIRD = THIRD
|
710
754
|
|
711
755
|
FOURTH = (events) ->
|
712
756
|
result = []
|
713
757
|
result = [events.sort(dateSortAscending)[3]] if (events.length > 3)
|
714
|
-
applySpecificOccurrenceSubset('FOURTH',
|
758
|
+
applySpecificOccurrenceSubset('FOURTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
715
759
|
@FOURTH = FOURTH
|
716
760
|
|
717
761
|
FIFTH = (events) ->
|
718
762
|
result = []
|
719
763
|
result = [events.sort(dateSortAscending)[4]] if (events.length > 4)
|
720
|
-
applySpecificOccurrenceSubset('FIFTH',
|
764
|
+
applySpecificOccurrenceSubset('FIFTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
721
765
|
@FIFTH = FIFTH
|
722
766
|
|
723
767
|
RECENT = (events) ->
|
724
768
|
result = []
|
725
769
|
result = [events.sort(dateSortDescending)[0]] if (events.length > 0)
|
726
|
-
applySpecificOccurrenceSubset('RECENT',
|
770
|
+
applySpecificOccurrenceSubset('RECENT',hqmf.SpecificsManager.maintainSpecifics(result, events))
|
727
771
|
@RECENT = RECENT
|
728
772
|
|
729
773
|
LAST = (events) ->
|
@@ -759,7 +803,7 @@ MIN = (events, range) ->
|
|
759
803
|
if (events.length > 0)
|
760
804
|
minValue = events.sort(valueSortAscending)[0].value()["scalar"]
|
761
805
|
result = new Boolean(range.match(minValue))
|
762
|
-
applySpecificOccurrenceSubset('MIN',
|
806
|
+
applySpecificOccurrenceSubset('MIN',hqmf.SpecificsManager.maintainSpecifics(result, events), range)
|
763
807
|
@MIN = MIN
|
764
808
|
|
765
809
|
MAX = (events, range) ->
|
@@ -767,9 +811,16 @@ MAX = (events, range) ->
|
|
767
811
|
if (events.length > 0)
|
768
812
|
maxValue = events.sort(valueSortDescending)[0].value()["scalar"]
|
769
813
|
result = new Boolean(range.match(maxValue))
|
770
|
-
applySpecificOccurrenceSubset('MAX',
|
814
|
+
applySpecificOccurrenceSubset('MAX',hqmf.SpecificsManager.maintainSpecifics(result, events), range)
|
771
815
|
@MAX = MAX
|
772
816
|
|
817
|
+
DATEDIFF = (events, range) ->
|
818
|
+
return hqmf.SpecificsManager.maintainSpecifics(new Boolean(false), events) if events.length < 2
|
819
|
+
throw "cannot calculate against more than 2 events" if events.length > 2
|
820
|
+
hqmf.SpecificsManager.maintainSpecifics(new Boolean(withinRange('DATEDIFF', getIVL(events[0]), getIVL(events[1]), range)), events)
|
821
|
+
@DATEDIFF = DATEDIFF
|
822
|
+
|
823
|
+
|
773
824
|
@OidDictionary = {};
|
774
825
|
|
775
826
|
hqmfjs = hqmfjs||{}
|