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 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
- #gem "hquery-patient-api", :git => 'http://github.com/pophealth/patientapi.git', :branch => 'develop'
12
- #gem 'hquery-patient-api', :path => '../patientapi'
13
- gem 'hquery-patient-api', '~> 0.3.0'
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.3)
5
- actionpack (= 3.2.3)
4
+ actionmailer (3.2.9)
5
+ actionpack (= 3.2.9)
6
6
  mail (~> 2.4.4)
7
- actionpack (3.2.3)
8
- activemodel (= 3.2.3)
9
- activesupport (= 3.2.3)
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.1)
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.2)
17
- activemodel (3.2.3)
18
- activesupport (= 3.2.3)
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.3)
21
- activemodel (= 3.2.3)
22
- activesupport (= 3.2.3)
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.3)
26
- activemodel (= 3.2.3)
27
- activesupport (= 3.2.3)
28
- activesupport (3.2.3)
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.2)
31
+ ansi (1.4.3)
32
32
  arel (3.0.2)
33
- awesome_print (1.0.2)
34
- builder (3.0.3)
33
+ awesome_print (1.1.0)
34
+ builder (3.0.4)
35
35
  choice (0.1.6)
36
- coderay (1.0.6)
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.3.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.3.0)
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.1.3)
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.6)
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.4)
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.3.0)
73
+ hquery-patient-api (1.0.0)
73
74
  httpauth (0.2.0)
74
75
  i18n (0.6.1)
75
- journey (1.0.3)
76
- json (1.7.3)
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.7.1)
88
- mime-types (1.18)
89
- minitest (2.12.1)
90
- mongoid (3.0.13)
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.2.9)
96
- multi_json (1.3.6)
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.10)
107
+ origin (1.0.11)
107
108
  polyglot (0.3.3)
108
- pry (0.9.9.3)
109
+ pry (0.9.10)
109
110
  coderay (~> 1.0.5)
110
- method_source (~> 0.7.1)
111
- slop (>= 2.4.4, < 3)
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.1)
118
+ rack-test (0.6.2)
118
119
  rack (>= 1.0)
119
- rails (3.2.3)
120
- actionmailer (= 3.2.3)
121
- actionpack (= 3.2.3)
122
- activerecord (= 3.2.3)
123
- activeresource (= 3.2.3)
124
- activesupport (= 3.2.3)
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.3)
127
- railties (3.2.3)
128
- actionpack (= 3.2.3)
129
- activesupport (= 3.2.3)
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 (~> 0.14.6)
134
- rake (0.9.2.2)
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.5)
147
+ ruby-ole (1.2.11.6)
147
148
  rubyzip (0.9.9)
148
- sass (3.1.15)
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 (2.4.4)
154
+ slop (3.3.3)
154
155
  spreadsheet (0.6.8)
155
156
  ruby-ole (>= 1.0)
156
- sprockets (2.1.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.14.6)
165
+ thor (0.16.0)
164
166
  tilt (1.3.3)
165
- todonotes (0.1.0)
167
+ todonotes (0.1.1)
166
168
  log4r
167
- treetop (1.4.10)
169
+ treetop (1.4.12)
168
170
  polyglot
169
171
  polyglot (>= 0.3.1)
170
- turn (0.9.5)
172
+ turn (0.9.6)
171
173
  ansi
172
- tzinfo (0.3.33)
173
- uglifier (1.2.4)
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.5)
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.1.3)
189
- hqmf-parser (~> 1.0.4)
190
- hquery-patient-api (~> 0.3.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.setFullYear(@date.getFullYear()+pq.value)
27
+ @date.setUTCFullYear(@date.getUTCFullYear()+pq.value)
28
28
  else if pq.unit=="mo"
29
- @date.setMonth(@date.getMonth()+pq.value)
29
+ @date.setUTCMonth(@date.getUTCMonth()+pq.value)
30
30
  else if pq.unit=="wk"
31
- @date.setDate(@date.getDate()+(7*pq.value))
31
+ @date.setUTCDate(@date.getUTCDate()+(7*pq.value))
32
32
  else if pq.unit=="d"
33
- @date.setDate(@date.getDate()+pq.value)
33
+ @date.setUTCDate(@date.getUTCDate()+pq.value)
34
34
  else if pq.unit=="h"
35
- @date.setHours(@date.getHours()+pq.value)
35
+ @date.setUTCHours(@date.getUTCHours()+pq.value)
36
36
  else if pq.unit=="min"
37
- @date.setMinutes(@date.getMinutes()+pq.value)
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.getMonth() < earlier.getMonth())
117
- later.getFullYear()-earlier.getFullYear()-1
118
- else if (later.getMonth() == earlier.getMonth() && later.getDate() >= earlier.getDate())
119
- later.getFullYear()-earlier.getFullYear()
120
- else if (later.getMonth() == earlier.getMonth() && later.getDate() < earlier.getDate())
121
- later.getFullYear()-earlier.getFullYear()-1
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.getFullYear()-earlier.getFullYear()
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.getDate() >= earlier.getDate())
128
- (later.getFullYear()-earlier.getFullYear())*12+later.getMonth()-earlier.getMonth()
127
+ if (later.getUTCDate() >= earlier.getUTCDate())
128
+ (later.getUTCFullYear()-earlier.getUTCFullYear())*12+later.getUTCMonth()-earlier.getUTCMonth()
129
129
  else
130
- (later.getFullYear()-earlier.getFullYear())*12+later.getMonth()-earlier.getMonth()-1
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.getFullYear(), earlier.getMonth(), earlier.getDate())
144
- e.setUTCHours(0)
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
- Specifics.unionAll(new Boolean(trueValues.length>0), values)
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
- Specifics.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
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
- Specifics.intersectAll(new Boolean(falseValues.length>0), values, true)
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
- Specifics.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
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
- Specifics.intersectAll(new CrossProduct(eventLists), eventLists)
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
- Specifics.unionAll(union, eventLists)
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', Specifics.maintainSpecifics(result, events), range)
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 Specifics.maintainSpecifics(matchingBounds,bounds)
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
- Specifics.maintainSpecifics(matchingBounds, bounds)
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 Specifics()
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: we'll need a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events))
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',Specifics.maintainSpecifics(result, events), range)
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',Specifics.maintainSpecifics(result, events), range)
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||{}