hqmf2js 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 1.9.2
4
+ - 1.9.3
5
5
 
6
6
  script: bundle exec rake
7
7
 
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hqmf2js (1.2.0)
4
+ hqmf2js (1.2.1)
5
5
  coffee-script (~> 2.2.0)
6
- health-data-standards (~> 3.0.1)
7
- hquery-patient-api (~> 1.0.1)
6
+ health-data-standards (~> 3.1.1)
7
+ hquery-patient-api (~> 1.0.2)
8
8
  nokogiri (~> 1.5.5)
9
9
  sprockets (~> 2.2.2)
10
10
  tilt (~> 1.3.3)
@@ -43,7 +43,6 @@ GEM
43
43
  arel (3.0.2)
44
44
  awesome_print (1.1.0)
45
45
  builder (3.0.4)
46
- choice (0.1.6)
47
46
  coderay (1.0.8)
48
47
  coffee-rails (3.2.2)
49
48
  coffee-script (>= 2.2.0)
@@ -60,34 +59,23 @@ GEM
60
59
  erubis (2.7.0)
61
60
  execjs (1.4.0)
62
61
  multi_json (~> 1.0)
63
- faraday (0.8.6)
64
- multipart-post (~> 1.1)
65
- google-spreadsheet-ruby (0.1.8)
66
- nokogiri (>= 1.4.3.1)
67
- oauth (>= 0.3.6)
68
- oauth2 (>= 0.5.0)
69
62
  hashie (1.2.0)
70
- health-data-standards (3.0.1)
63
+ health-data-standards (3.1.1)
71
64
  activesupport (~> 3.2.9)
72
65
  builder (~> 3.0.0)
73
66
  erubis (~> 2.7.0)
74
- google-spreadsheet-ruby (= 0.1.8)
75
67
  log4r (~> 1.1.10)
68
+ memoist (~> 0.9.0)
76
69
  mongoid (~> 3.1.0)
77
70
  nokogiri (~> 1.5.5)
78
71
  rest-client (~> 1.6.7)
79
- roo (= 1.10.1)
80
72
  rubyzip
81
- spreadsheet (= 0.6.8)
82
73
  uuid (~> 2.3.5)
83
74
  hike (1.2.1)
84
- hquery-patient-api (1.0.1)
85
- httpauth (0.2.0)
75
+ hquery-patient-api (1.0.2)
86
76
  i18n (0.6.1)
87
77
  journey (1.0.4)
88
78
  json (1.7.5)
89
- jwt (0.1.5)
90
- multi_json (>= 1.0)
91
79
  libv8 (3.3.10.4)
92
80
  log4r (1.1.10)
93
81
  macaddr (1.6.1)
@@ -96,27 +84,18 @@ GEM
96
84
  i18n (>= 0.4.0)
97
85
  mime-types (~> 1.16)
98
86
  treetop (~> 1.4.8)
87
+ memoist (0.9.0)
99
88
  method_source (0.8.1)
100
89
  mime-types (1.20.1)
101
90
  minitest (4.3.2)
102
- mongoid (3.1.2)
91
+ mongoid (3.1.3)
103
92
  activemodel (~> 3.2)
104
93
  moped (~> 1.4.2)
105
94
  origin (~> 1.0)
106
95
  tzinfo (~> 0.3.22)
107
- moped (1.4.2)
96
+ moped (1.4.5)
108
97
  multi_json (1.5.0)
109
- multi_xml (0.5.3)
110
- multipart-post (1.2.0)
111
98
  nokogiri (1.5.6)
112
- oauth (0.4.7)
113
- oauth2 (0.9.1)
114
- faraday (~> 0.8)
115
- httpauth (~> 0.1)
116
- jwt (~> 0.1.4)
117
- multi_json (~> 1.0)
118
- multi_xml (~> 0.5)
119
- rack (~> 1.2)
120
99
  origin (1.0.11)
121
100
  polyglot (0.3.3)
122
101
  pry (0.9.10)
@@ -150,14 +129,6 @@ GEM
150
129
  json (~> 1.4)
151
130
  rest-client (1.6.7)
152
131
  mime-types (>= 1.16)
153
- roo (1.10.1)
154
- choice (>= 0.1.4)
155
- google-spreadsheet-ruby (>= 0.1.5)
156
- nokogiri (>= 1.5.0)
157
- rubyzip (>= 0.9.4)
158
- spreadsheet (> 0.6.4)
159
- todonotes (>= 0.1.0)
160
- ruby-ole (1.2.11.6)
161
132
  rubyzip (0.9.9)
162
133
  sass (3.2.3)
163
134
  sass-rails (3.2.5)
@@ -165,8 +136,6 @@ GEM
165
136
  sass (>= 3.1.10)
166
137
  tilt (~> 1.3)
167
138
  slop (3.3.3)
168
- spreadsheet (0.6.8)
169
- ruby-ole (>= 1.0)
170
139
  sprockets (2.2.2)
171
140
  hike (~> 1.2)
172
141
  multi_json (~> 1.0)
@@ -177,8 +146,6 @@ GEM
177
146
  libv8 (~> 3.3.10)
178
147
  thor (0.16.0)
179
148
  tilt (1.3.3)
180
- todonotes (0.1.1)
181
- log4r
182
149
  treetop (1.4.12)
183
150
  polyglot
184
151
  polyglot (>= 0.3.1)
@@ -0,0 +1,72 @@
1
+ class @CrosswalkManager
2
+ @matchedSystems: {}
3
+ @trueMatchedSystems: {}
4
+ @tmpTrueMatchedSystems: {}
5
+ @clearValidateCodeSystemData: () ->
6
+ CrosswalkManager.matchedSystems = {}
7
+ CrosswalkManager.trueMatchedSystems = {}
8
+ CrosswalkManager.tmpTrueMatchedSystems = {}
9
+
10
+ hQuery.Patient::validateCodeSystems = () ->
11
+ sections = ['encounters','medications','conditions','procedures','results','vitalSigns','immunizations','allergies','pregnancies','socialHistories','careGoals','medicalEquipment','functionalStatuses']
12
+ fullMatch = true
13
+ for section in sections
14
+ for entry in this[section]()
15
+ matchedSystems = CrosswalkManager.matchedSystems[entry.id]
16
+ if (matchedSystems? && _.keys(matchedSystems).length > 0)
17
+ matches = _.keys(entry.json.codes).length == _.keys(matchedSystems).length
18
+ fullMatch = fullMatch && matches
19
+ Logger.info("#{entry.json['description']} -> #{_.keys(entry.json.codes)} != #{_.keys(matchedSystems)}") if !matches
20
+ # trueMatchedSystems = CrosswalkManager.trueMatchedSystems[entry.id]
21
+ # if (trueMatchedSystems? && _.keys(trueMatchedSystems).length > 0)
22
+ # matches = _.keys(entry.json.codes).length == _.keys(trueMatchedSystems).length
23
+ # fullMatch = fullMatch && matches
24
+ # Logger.info("TRUE MATCH: #{entry.json['description']} -> #{_.keys(entry.json.codes)} != #{_.keys(trueMatchedSystems)}") if !matches
25
+ CrosswalkManager.clearValidateCodeSystemData()
26
+ fullMatch
27
+
28
+ hQuery.CodedEntry::includesCodeFrom = (codeSet) ->
29
+ allTrue = true
30
+ oneTrue = false
31
+ # tmpTrueMatchedSystems = {}
32
+ matchedSystems = CrosswalkManager.matchedSystems[@id]
33
+ for codedValue in @_type
34
+ thisResult = codedValue.includedIn(codeSet)
35
+ oneTrue = oneTrue || thisResult
36
+ allTrue = allTrue && thisResult
37
+ matchedSystems = {} unless matchedSystems?
38
+ matchedSystems[codedValue.codeSystemName()] = true if (thisResult)
39
+ # tmpTrueMatchedSystems[codedValue.codeSystemName()] = true if (thisResult)
40
+ if (oneTrue && !allTrue)
41
+ Logger.info("*** #{@json['description']}")
42
+ for codedValue in @_type
43
+ thisResult = codedValue.includedIn(codeSet)
44
+ Logger.info("*** Logger is #{thisResult} for: #{Logger.toJson(codedValue)}")
45
+ CrosswalkManager.matchedSystems[@id] = matchedSystems
46
+ # CrosswalkManager.tmpTrueMatchedSystems[@id] = tmpTrueMatchedSystems
47
+ oneTrue
48
+
49
+ instrumentTrueCrosswalk = (hqmfjs) ->
50
+ # CrosswalkManager.clearValidateCodeSystemData()
51
+ # _.each(_.functions(hqmfjs), (method) ->
52
+ # hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
53
+
54
+ # args = Array.prototype.slice.call(arguments,1)
55
+
56
+ # results = func.apply(this, args)
57
+ # tmp_results = results
58
+ # tmp_results = [results] unless _.isArray(tmp_results)
59
+
60
+ # _.each(tmp_results, (result) ->
61
+ # if result.json? && CrosswalkManager.tmpTrueMatchedSystems[result.id]?
62
+ # tmpTrueMatchedSystems = CrosswalkManager.tmpTrueMatchedSystems[result.id]
63
+ # CrosswalkManager.trueMatchedSystems[result.id] = {} unless CrosswalkManager.trueMatchedSystems[result.id]
64
+ # Logger.info("TRUE_MATCHED: #{result.json['description']} - #{_.keys(tmpTrueMatchedSystems)}!!!")
65
+ # _.each(_.keys(tmpTrueMatchedSystems), (key) ->
66
+ # CrosswalkManager.trueMatchedSystems[result.id][key] = CrosswalkManager.trueMatchedSystems[result.id][key] || tmpTrueMatchedSystems[key]
67
+ # )
68
+ # )
69
+ # results
70
+ # )
71
+ # )
72
+ @instrumentTrueCrosswalk = instrumentTrueCrosswalk
@@ -131,7 +131,8 @@ class TS
131
131
 
132
132
  # Number of whole minutes between the two time stamps (as Date objects)
133
133
  @minutesDifference: (earlier, later) ->
134
- Math.floor(((later.getTime()-earlier.getTime())/1000)/60)
134
+ [e,l] = TS.dropSeconds(earlier,later)
135
+ Math.floor(((l.getTime()-e.getTime())/1000)/60)
135
136
 
136
137
  # Number of whole hours between the two time stamps (as Date objects)
137
138
  @hoursDifference: (earlier, later) ->
@@ -452,7 +453,8 @@ filterEventsByValue = (events, value) ->
452
453
  # Return only those events with a field that matches the supplied value
453
454
  filterEventsByField = (events, field, value) ->
454
455
  respondingEvents = (event for event in events when event.respondTo(field))
455
- result = (event for event in respondingEvents when value.match(event[field]()))
456
+ unit = value.unit() if value.unit?
457
+ result = (event for event in respondingEvents when value.match(event[field](unit)))
456
458
  hqmf.SpecificsManager.maintainSpecifics(result, events)
457
459
  @filterEventsByField = filterEventsByField
458
460
 
@@ -510,10 +512,13 @@ class CrossProduct extends Array
510
512
  constructor: (allEventLists) ->
511
513
  super()
512
514
  @eventLists = []
515
+ # keep track of the specific occurrences by encounter ID. This is used in eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
516
+ @specific_occurrence = {}
513
517
  for eventList in allEventLists
514
518
  @eventLists.push eventList
515
519
  for event in eventList
516
520
  this.push(event)
521
+ @specific_occurrence[event.id] = eventList.specific_occurrence if eventList.specific_occurrence
517
522
  listCount: -> @eventLists.length
518
523
  childList: (index) -> @eventLists[index]
519
524
 
@@ -525,9 +530,13 @@ XPRODUCT = (eventLists...) ->
525
530
  # Create a new list containing all the events from the supplied event lists
526
531
  UNION = (eventLists...) ->
527
532
  union = []
533
+ # keep track of the specific occurrences by encounter ID. This is used in eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
534
+ specific_occurrence = {}
528
535
  for eventList in eventLists
529
536
  for event in eventList
537
+ specific_occurrence[event.id] = eventList.specific_occurrence if eventList.specific_occurrence
530
538
  union.push(event)
539
+ union.specific_occurrence = specific_occurrence unless _.isEmpty(specific_occurrence)
531
540
  hqmf.SpecificsManager.unionAll(union, eventLists)
532
541
  @UNION = UNION
533
542
 
@@ -639,7 +648,7 @@ eventsMatchBounds = (events, bounds, methodName, range) ->
639
648
 
640
649
  if hasSpecificOccurrence
641
650
  matchingEvents.specific_occurrence = events.specific_occurrence
642
- # 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
651
+ # we use a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
643
652
  specificContext.addRows(Row.buildRowsForMatching(events.specific_occurrence, event, bounds.specific_occurrence, matchingBounds))
644
653
  else
645
654
  # add all stars
@@ -2,11 +2,13 @@ class @Logger
2
2
  @logger: []
3
3
  @rationale: {}
4
4
  @info: (string) ->
5
- @logger.push("#{Logger.indent()}#{string}")
5
+ if @enable_logging
6
+ @logger.push("#{Logger.indent()}#{string}")
6
7
  @record: (id, result) ->
7
- if result? and typeof(result.isTrue) == 'function'
8
+ if @enable_rationale and result? and typeof(result.isTrue) == 'function'
8
9
  @rationale[id] = result.isTrue()
9
- @enabled: true
10
+ @enable_logging: true
11
+ @enable_rationale: true
10
12
  @initialized: false
11
13
  @indentCount = 0
12
14
  @indent: ->
@@ -24,10 +26,10 @@ class @Logger
24
26
  else
25
27
  object
26
28
  @toJson: (value) ->
27
- if (typeof(tojson) == 'function')
28
- tojson(value)
29
- else
29
+ if (typeof(JSON) == 'object')
30
30
  JSON.stringify(value)
31
+ else
32
+ tojson(value)
31
33
  @classNameFor: (object) ->
32
34
  funcNameRegex = ///function (.+)\(///;
33
35
  results = funcNameRegex.exec(object.constructor.toString());
@@ -40,29 +42,61 @@ class @Logger
40
42
  memo.push("#{entry.codeSystemName()}:#{entry.code()}");
41
43
  memo
42
44
  , []).join(',')+"]"
45
+ @formatSpecificEntry: (object, index) ->
46
+ if object == hqmf.SpecificsManager.any
47
+ object
48
+ else
49
+ "#{object.id}"
50
+ @formatSpecificContext: (object) ->
51
+ displayRows = []
52
+ if object?.specificContext?.rows?.length
53
+ displayRows.push(Logger.toJson(item.id for item in hqmf.SpecificsManager.occurrences))
54
+ for row in object.specificContext.rows
55
+ do (row) ->
56
+ displayRow = []
57
+ for entry, index in row.values
58
+ do (entry) ->
59
+ displayRow.push(Logger.formatSpecificEntry(entry, index))
60
+ displayRows.push(Logger.toJson(displayRow))
61
+ displayRows
62
+ @logSpecificContext: (object) ->
63
+ Logger.indentCount++
64
+ for row in Logger.formatSpecificContext(object)
65
+ do (row) ->
66
+ Logger.info(row)
67
+ Logger.indentCount--
43
68
 
69
+
70
+ @injectLogger = (hqmfjs, enable_logging, enable_rationale) ->
71
+ Logger.enable_logging = enable_logging
72
+ Logger.enable_rationale = enable_rationale
44
73
 
45
- @enableMeasureLogging = (hqmfjs) ->
74
+ # Wrap all of the data criteria functions generated from HQMF
46
75
  _.each(_.functions(hqmfjs), (method) ->
47
- hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
76
+ if method != 'initializeSpecifics'
77
+ hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
48
78
 
49
- args = Array.prototype.slice.call(arguments,1)
79
+ args = Array.prototype.slice.call(arguments,1)
50
80
 
51
- Logger.info("#{method}:")
52
- Logger.indentCount++
53
- result = func.apply(this, args)
81
+ Logger.info("#{method}:")
82
+ Logger.indentCount++
83
+ result = func.apply(this, args)
54
84
 
55
- Logger.indentCount--
56
- Logger.info("#{method} -> #{Logger.asBoolean(result)}")
57
- Logger.record(method,result)
58
- return result;
59
- );
85
+ Logger.indentCount--
86
+ Logger.info("#{method} -> #{Logger.asBoolean(result)}")
87
+ if result.specificContext?.rows?.length
88
+ Logger.info("Specific context")
89
+ Logger.logSpecificContext(result)
90
+ Logger.info("------")
91
+ Logger.record(method,result)
92
+ return result;
93
+ );
60
94
  );
61
95
 
62
- @enableLogging =->
63
96
  if (!Logger.initialized)
64
97
  Logger.initialized=true
65
98
 
99
+ # Wrap selected hQuery Patient API functions
66
100
  _.each(_.functions(hQuery.Patient.prototype), (method) ->
67
101
  if (hQuery.Patient.prototype[method].length == 0)
68
102
  hQuery.Patient.prototype[method] = _.wrap(hQuery.Patient.prototype[method], (func) ->
@@ -88,6 +122,18 @@ class @Logger
88
122
  return result;
89
123
  );
90
124
 
125
+ # Wrap selected HQMF Util functions
126
+ hqmf.SpecificsManagerSingleton.prototype.intersectAll = _.wrap(hqmf.SpecificsManagerSingleton.prototype.intersectAll, (func, boolVal, values, negate=false, episodeIndices) ->
127
+ func = _.bind(func, this, boolVal, values, negate, episodeIndices)
128
+ result = func(boolVal, values, negate, episodeIndices)
129
+ Logger.info("Intersecting (#{values.length}):")
130
+ for value in values
131
+ Logger.logSpecificContext(value)
132
+ Logger.info("Intersected result:")
133
+ Logger.logSpecificContext(result)
134
+ return result;
135
+ );
136
+
91
137
  @getCodes = _.wrap(@getCodes, (func, oid) ->
92
138
  codes = func(oid)
93
139
  Logger.info("accessed codes: #{oid}")
@@ -127,6 +173,13 @@ class @Logger
127
173
  result
128
174
  )
129
175
 
176
+ @eventsMatchBounds = _.wrap(@eventsMatchBounds, (func, events, bounds, methodName, range) ->
177
+ args = Array.prototype.slice.call(arguments,1)
178
+ result = func(events, bounds, methodName, range)
179
+ Logger.info("#{methodName}(Events: #{Logger.stringify(events)}, Bounds: #{Logger.stringify(bounds)}, Range: #{Logger.toJson(range)}) -> #{Logger.stringify(result)}")
180
+ result
181
+ )
182
+
130
183
  @atLeastOneFalse = _.wrap(@atLeastOneFalse, (func) ->
131
184
  args = Array.prototype.slice.call(arguments,1)
132
185
  Logger.info("called atLeastOneFalse(#{args}):")
@@ -138,9 +191,3 @@ class @Logger
138
191
  result
139
192
  )
140
193
 
141
- @eventsMatchBounds = _.wrap(@eventsMatchBounds, (func, events, bounds, methodName, range) ->
142
- args = Array.prototype.slice.call(arguments,1)
143
- result = func(events, bounds, methodName, range)
144
- Logger.info("#{methodName}(Events: #{Logger.stringify(events)}, Bounds: #{Logger.stringify(bounds)}, Range: #{Logger.toJson(range)}) -> #{Logger.stringify(result)}")
145
- result
146
- )
@@ -18,6 +18,10 @@ hQuery.CodedEntry::asTS = ->
18
18
  ts.date = this.timeStamp()
19
19
  ts
20
20
 
21
+ hQuery.Encounter::lengthOfStay = (unit) ->
22
+ ivl_ts = this.asIVL_TS()
23
+ ivl_ts.low.difference(ivl_ts.high, unit)
24
+
21
25
  hQuery.CodedEntry::respondTo = (functionName) ->
22
26
  typeof(@[functionName]) == "function"
23
27
 
@@ -73,8 +73,13 @@ class hqmf.SpecificsManagerSingleton
73
73
  entry.specificRow = row
74
74
  entry
75
75
 
76
- intersectSpecifics: (populations...) ->
77
- value = @intersectAll(new Boolean(populations[0].isTrue()), populations)
76
+ intersectSpecifics: (nextPopulation, previousPopulation, occurrenceIDs) ->
77
+ # we need to pass the episode indicies all the way down through the interesection to the match function
78
+ # this must be done because we need to ensure that on intersection of populations the * does not allow an episode through
79
+ # that was not part of a previous population
80
+ episodeIndices = null
81
+ episodeIndices = (@getColumnIndex(occurrenceID) for occurrenceID in occurrenceIDs) if occurrenceIDs?
82
+ value = @intersectAll(new Boolean(nextPopulation.isTrue()), [nextPopulation, previousPopulation], false, episodeIndices)
78
83
  value
79
84
 
80
85
  # Returns a count of the unique events that match the criteria for the supplied
@@ -104,19 +109,19 @@ class hqmf.SpecificsManagerSingleton
104
109
  return @maintainSpecifics(new Boolean(false), initial)
105
110
  else
106
111
  return initial
107
-
112
+
108
113
  # Returns a boolean indication of whether all of the supplied population criteria are
109
114
  # met
110
115
  validate: (intersectedPopulation) ->
111
116
  intersectedPopulation.isTrue() and intersectedPopulation.specificContext.hasRows()
112
117
 
113
- intersectAll: (boolVal, values, negate=false) ->
118
+ intersectAll: (boolVal, values, negate=false, episodeIndices) ->
114
119
  result = new hqmf.SpecificOccurrence
115
120
  # add identity row
116
121
  result.addIdentityRow()
117
122
  for value in values
118
123
  if value.specificContext?
119
- result = result.intersect(value.specificContext)
124
+ result = result.intersect(value.specificContext, episodeIndices)
120
125
  if negate and (!result.hasRows() or result.hasSpecifics())
121
126
  result = result.negate()
122
127
  result = result.compactReusedEvents()
@@ -202,11 +207,11 @@ class hqmf.SpecificOccurrence
202
207
  value.rows = @rows.concat(other.rows)
203
208
  value.removeDuplicateRows()
204
209
 
205
- intersect: (other) ->
210
+ intersect: (other, episodeIndices) ->
206
211
  value = new hqmf.SpecificOccurrence()
207
212
  for leftRow in @rows
208
213
  for rightRow in other.rows
209
- result = leftRow.intersect(rightRow)
214
+ result = leftRow.intersect(rightRow, episodeIndices)
210
215
  value.rows.push(result) if result?
211
216
  value.removeDuplicateRows()
212
217
 
@@ -333,8 +338,6 @@ class hqmf.SpecificOccurrence
333
338
  addIdentityRow: ->
334
339
  @addRows(hqmf.SpecificsManager.identity().rows)
335
340
 
336
-
337
-
338
341
  class Row
339
342
  # {'OccurrenceAEncounter':1, 'OccurrenceBEncounter'2}
340
343
  constructor: (leftMost, occurrences={}) ->
@@ -370,18 +373,30 @@ class Row
370
373
  equal &&= Row.valuesEqual(value, other.values[i])
371
374
  equal
372
375
 
373
- intersect: (other) ->
376
+ intersect: (other, episodeIndices) ->
374
377
  intersectedRow = new Row(@leftMost, {})
375
378
  intersectedRow.tempValue = @tempValue
376
- allMatch = true
379
+
380
+ # if all the episodes are any, then they were not referenced by the parent population. This occurs when an intersection is done
381
+ # against the identity row. In this case we want to allow the specific occurrences through. This happens when we intersect against a measure
382
+ # without a denomninator, and on regular intersections since we start with the identity row in the context.
383
+ allEpisodesAny = (episodeIndices? && (@allValuesAny(episodeIndices) || other.allValuesAny(episodeIndices)))
384
+
377
385
  for value,i in @values
378
- result = Row.match(value, other.values[i])
386
+ # check if the value is an episode of care. If so it will be treated differently in the match function
387
+ isEpisodeOfCare = (episodeIndices? && !allEpisodesAny && episodeIndices.indexOf(i) >= 0)
388
+ result = Row.match(value, other.values[i], isEpisodeOfCare)
379
389
  if result?
380
390
  intersectedRow.values[i] = result
381
391
  else
382
392
  return undefined
383
393
  intersectedRow
384
394
 
395
+ allValuesAny: (indicies) ->
396
+ for i in indicies
397
+ return false if @values[i] != hqmf.SpecificsManager.any
398
+ return true
399
+
385
400
  groupKeyForLeftMost: ->
386
401
  @groupKey(@leftMost)
387
402
 
@@ -397,12 +412,20 @@ class Row
397
412
  keyForGroup
398
413
 
399
414
 
400
- @match: (left, right) ->
401
- return right if left == hqmf.SpecificsManager.any
402
- return left if right == hqmf.SpecificsManager.any
415
+ @match: (left, right, isEpisodeOfCare) ->
416
+ return @checkEpisodeOfCare(right, isEpisodeOfCare) if left == hqmf.SpecificsManager.any
417
+ return @checkEpisodeOfCare(left, isEpisodeOfCare) if right == hqmf.SpecificsManager.any
403
418
  return left if left.id == right.id
404
419
  return undefined
405
420
 
421
+ # if we are dealing with an episode of care we don't want to match against the any (*) indicator. This is because
422
+ # the any indicator from a previous population indicates that we did not evaluate against that occurrence in a positive path.
423
+ # this is typically OK with specific occurrences, but not if they represent episodes of care.
424
+ @checkEpisodeOfCare: (value, isEpisodeOfCare) ->
425
+ # return the any indicator to signify that the episode of care was unobserved. This will eliminate it from the counts.
426
+ return hqmf.SpecificsManager.any if (isEpisodeOfCare)
427
+ return value
428
+
406
429
  @valuesEqual: (left, right) ->
407
430
  return true if !left? and !right?
408
431
  return false if !left?
@@ -417,7 +440,12 @@ class Row
417
440
  for match in matches
418
441
  occurrences={}
419
442
  occurrences[entryKey] = entry
420
- occurrences[matchesKey] = match
443
+ # from unions and crossproducts we may have a matches key that is a hash of object ids mapped to the specific occurrence key.
444
+ # this is because we may have multiple different specific occurrences on the right hand side if it came from a group
445
+ if (_.isObject(matchesKey))
446
+ occurrences[matchesKey[match.id]] = match
447
+ else
448
+ occurrences[matchesKey] = match
421
449
  rows.push(new Row(entryKey, occurrences))
422
450
  rows
423
451
 
data/hqmf2js.gemspec CHANGED
@@ -7,15 +7,15 @@ Gem::Specification.new do |s|
7
7
  s.email = "hquery-talk@googlegroups.com"
8
8
  s.homepage = "http://github.com/hquery/hqmf2js"
9
9
  s.authors = ["Marc Hadley", "Andre Quina", "Andy Gregorowicz"]
10
- s.version = '1.2.0'
10
+ s.version = '1.2.1'
11
11
 
12
12
  s.add_dependency 'nokogiri', '~> 1.5.5'
13
13
  s.add_dependency 'tilt', '~> 1.3.3'
14
14
  s.add_dependency 'coffee-script', '~> 2.2.0'
15
15
  s.add_dependency 'sprockets', '~> 2.2.2'
16
16
  s.add_development_dependency "awesome_print", "~> 1.1.0"
17
- s.add_dependency 'health-data-standards', '~> 3.0.1'
18
- s.add_dependency 'hquery-patient-api', '~> 1.0.1'
17
+ s.add_dependency 'health-data-standards', '~> 3.1.1'
18
+ s.add_dependency 'hquery-patient-api', '~> 1.0.2'
19
19
 
20
20
  s.files = s.files = `git ls-files`.split("\n")
21
21
  end
@@ -1,4 +1,4 @@
1
- var value = patient.<%= criteria.property %>(<%= js_for_date_bound(criteria) if criteria.property == :age %>);
1
+ var value = patient.<%= criteria.property %>(<%= js_for_date_bound(criteria) if criteria.property == :age %>) || null;
2
2
  <%- if criteria.property == :birthtime -%>
3
3
  var events = [value];
4
4
  <%- if criteria.temporal_references -%>
@@ -1,10 +1,6 @@
1
1
  module HQMF2JS
2
2
  module Generator
3
3
  class CodesToJson
4
- def self.from_xls(code_systems_file)
5
- value_sets = HQMF::ValueSet::Parser.new().parse(code_systems_file)
6
- from_value_sets(value_sets)
7
- end
8
4
 
9
5
  def self.hash_to_js(hash)
10
6
  hash.to_json.gsub(/\"/, "'")
data/lib/generator/js.rb CHANGED
@@ -240,25 +240,33 @@ module HQMF2JS
240
240
  HQMF2JS::Generator.render_template('data_criteria', {'all_criteria' => @doc.specific_occurrence_source_data_criteria.concat(@doc.all_data_criteria), 'measure_period' => @doc.measure_period})
241
241
  end
242
242
 
243
- def self.library_functions
243
+ def self.library_functions(check_crosswalk=false)
244
244
  ctx = Sprockets::Environment.new(File.expand_path("../../..", __FILE__))
245
245
  Tilt::CoffeeScriptTemplate.default_bare = true
246
246
  ctx.append_path "app/assets/javascripts"
247
247
 
248
- ["// #########################\n// ###### Underscore.js #######\n// #######################\n",
249
- ctx.find_asset('underscore').to_s,
250
- "// #########################\n// ###### PATIENT API #######\n// #########################\n",
251
- HqueryPatientApi::Generator.patient_api_javascript.to_s,
252
- "// #########################\n// ## SPECIFIC OCCURRENCES ##\n// #########################\n",
253
- ctx.find_asset('specifics').to_s,
254
- "// #########################\n// ### LIBRARY FUNCTIONS ####\n// #########################\n",
255
- ctx.find_asset('hqmf_util').to_s,
256
- "// #########################\n// ### PATIENT EXTENSION ####\n// #########################\n",
257
- ctx.find_asset('patient_api_extension').to_s,
258
- "// #########################\n// ## CUSTOM CALCULATIONS ###\n// #########################\n",
259
- ctx.find_asset('custom_calculations').to_s,
260
- "// #########################\n// ##### LOGGING UTILS ######\n// #########################\n",
261
- ctx.find_asset('logging_utils').to_s].join("\n")
248
+ libraries = ["// #########################\n// ###### Underscore.js #######\n// #######################\n",
249
+ ctx.find_asset('underscore').to_s,
250
+ "// #########################\n// ###### PATIENT API #######\n// #########################\n",
251
+ HqueryPatientApi::Generator.patient_api_javascript.to_s,
252
+ "// #########################\n// ## SPECIFIC OCCURRENCES ##\n// #########################\n",
253
+ ctx.find_asset('specifics').to_s,
254
+ "// #########################\n// ### LIBRARY FUNCTIONS ####\n// #########################\n",
255
+ ctx.find_asset('hqmf_util').to_s,
256
+ "// #########################\n// ### PATIENT EXTENSION ####\n// #########################\n",
257
+ ctx.find_asset('patient_api_extension').to_s,
258
+ "// #########################\n// ## CUSTOM CALCULATIONS ###\n// #########################\n",
259
+ ctx.find_asset('custom_calculations').to_s,
260
+ "// #########################\n// ##### LOGGING UTILS ######\n// #########################\n",
261
+ ctx.find_asset('logging_utils').to_s]
262
+
263
+ # check for code set crosswalks
264
+ if (check_crosswalk)
265
+ libraries += ["// #########################\n// ##### CROSSWALK EXTENSION ######\n// #########################\n",
266
+ ctx.find_asset('crosswalk').to_s]
267
+ end
268
+
269
+ libraries.join("\n")
262
270
 
263
271
  end
264
272
 
@@ -20,19 +20,5 @@ class CodesToJsonTest < Test::Unit::TestCase
20
20
 
21
21
  end
22
22
 
23
- def test_parsing_from_xls
24
-
25
- codes_file_path = File.expand_path("../../fixtures/codes/codes.xls", __FILE__)
26
- # Parse the code systems that are mapped to the OIDs we support
27
- codes_json = HQMF2JS::Generator::CodesToJson.hash_to_js(HQMF2JS::Generator::CodesToJson.from_xls(codes_file_path))
28
-
29
- @context = get_js_context("var dictionary = #{codes_json}")
30
- @context.eval("dictionary").entries.length.must_equal 12
31
- @context.eval("dictionary['2.16.840.1.113883.3.464.0001.430']").entries.first[0].must_equal "RxNorm"
32
- @context.eval("dictionary['2.16.840.1.113883.3.464.0001.430']").entries.first[1].length.must_equal 25
33
-
34
- end
35
-
36
-
37
23
 
38
24
  end
@@ -178,6 +178,14 @@ class LibraryFunctionTest < Test::Unit::TestCase
178
178
  ts2 = 'new TS("201203010020")'
179
179
  assert_equal 70, @context.eval("#{ts1}.difference(#{ts2},'min')")
180
180
 
181
+ ts1 = 'new TS("20120101101010")'
182
+ ts2 = 'new TS("20120101101030")'
183
+ assert_equal 0, @context.eval("#{ts1}.difference(#{ts2},'min')")
184
+
185
+ ts1 = 'new TS("20120101100950")'
186
+ ts2 = 'new TS("20120101101010")'
187
+ assert_equal 1, @context.eval("#{ts1}.difference(#{ts2},'min')")
188
+
181
189
  # Additional tests from previous version of TJC guidance
182
190
  ts4 = 'new TS("20000310")'
183
191
  ts5 = 'new TS("20110405")'
@@ -19,7 +19,7 @@ class SpecificsTest < Test::Unit::TestCase
19
19
  end
20
20
 
21
21
 
22
- def test_specifics_initialized_proper
22
+ def test_specifics_initialized_properly
23
23
 
24
24
  @context.eval('hqmf.SpecificsManager.keyLookup[0]').must_equal 'OccurrenceAEncounter'
25
25
  @context.eval('hqmf.SpecificsManager.keyLookup[1]').must_equal 'OccurrenceBEncounter'
@@ -593,12 +593,100 @@ class SpecificsTest < Test::Unit::TestCase
593
593
  "
594
594
  @context.eval(rows)
595
595
 
596
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop3))').must_equal true
597
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop4))').must_equal false
598
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop5))').must_equal false
599
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop3f,pop1,pop2))').must_equal false
596
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop3)))').must_equal true
597
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop4)))').must_equal false
598
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop5)))').must_equal false
599
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop3f,hqmf.SpecificsManager.intersectSpecifics(pop1,pop2)))').must_equal false
600
600
 
601
601
  end
602
+
603
+ def test_episode_of_care_restrictions
604
+
605
+ rows = "
606
+ hqmf.SpecificsManager.initialize({},hqmfjs, {'id':'OccurrenceAEncounter1', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter1'},
607
+ {'id':'OccurrenceAEncounter2', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter2'},
608
+ {'id':'OccurrenceAEncounter3', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter3'})
609
+
610
+
611
+ var row1 = new Row('OccurrenceAEncounter1',{'OccurrenceAEncounter1':{'id':1}});
612
+ var row2 = new Row('OccurrenceAEncounter2',{'OccurrenceAEncounter2':{'id':3}});
613
+ var row3 = new Row('OccurrenceAEncounter1',{'OccurrenceAEncounter1':{'id':1},'OccurrenceAEncounter2':{'id':3}});
614
+ var identityRow = hqmf.SpecificsManager.identity().rows[0];
615
+
616
+ var pop1 = new Boolean(true);
617
+ var pop2 = new Boolean(true);
618
+ var pop3 = new Boolean(true);
619
+ var pop4 = new Boolean(true);
620
+
621
+ pop1.specificContext = new hqmf.SpecificOccurrence([row1]);
622
+ pop2.specificContext = new hqmf.SpecificOccurrence([row2]);
623
+ pop3.specificContext = new hqmf.SpecificOccurrence([row3]);
624
+ pop4.specificContext = new hqmf.SpecificOccurrence([identityRow]);
625
+
626
+ var result = null;
627
+
628
+ "
629
+ @context.eval(rows)
630
+
631
+ # test allValuesAny
632
+ @context.eval('row1.allValuesAny([0,1,2])').must_equal false
633
+ @context.eval('row1.allValuesAny([1,2])').must_equal true
634
+ @context.eval('row1.allValuesAny([2])').must_equal true
635
+ @context.eval('row1.allValuesAny([1])').must_equal true
636
+ @context.eval('row1.allValuesAny([])').must_equal true
637
+ @context.eval('identityRow.allValuesAny([0,1,2])').must_equal true
638
+
639
+ # test checkEpisodeOfCare
640
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, true) == hqmf.SpecificsManager.any').must_equal true
641
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, false) == hqmf.SpecificsManager.any').must_equal false
642
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, false).id == 1').must_equal true
643
+
644
+ # test intersect
645
+ @context.eval('row1.intersect(row2,[0,1]).allValuesAny([0,1,2])').must_equal true # this is the critical check. Make sure we drop bad episode of care intersections
646
+ @context.eval('row1.intersect(row2,[0]).allValuesAny([2])').must_equal true
647
+ @context.eval('row1.intersect(row2,[0]).values[0].id == 1').must_equal true
648
+ @context.eval('row1.intersect(row2,[0]).values[1].id == 3').must_equal true
649
+ @context.eval('row1.intersect(row2,[1]).allValuesAny([2])').must_equal true
650
+ @context.eval('row1.intersect(row2,[1]).values[0].id == 1').must_equal true
651
+ @context.eval('row1.intersect(row2,[1]).values[1].id == 3').must_equal true
652
+
653
+ @context.eval('identityRow.intersect(row1,[0]).values[0].id == 1').must_equal true
654
+ @context.eval('identityRow.intersect(row1,[0]).allValuesAny([1,2])').must_equal true
655
+ @context.eval('row1.intersect(identityRow,[0]).values[0].id == 1').must_equal true
656
+ @context.eval('row1.intersect(identityRow,[0]).allValuesAny([1,2])').must_equal true
657
+
658
+ # make sure we drop a bad strggler for encounter 2
659
+ @context.eval('row1.intersect(row3,[0,1]).allValuesAny([1,2])').must_equal true
660
+ @context.eval('row1.intersect(row3,[0,1]).values[0].id == 1').must_equal true
661
+
662
+ # test intersectSpecifics
663
+
664
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[0].id == 1').must_equal true
665
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[1].id == 3').must_equal true
666
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[2] == hqmf.SpecificsManager.any').must_equal true
667
+ @context.eval("hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter1','OccurrenceAEncounter2','OccurrenceAEncounter3']).specificContext.rows[0].allValuesAny([0,1,2])").must_equal true
668
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter1']).specificContext.rows[0]")
669
+ @context.eval('result.allValuesAny([2])').must_equal true
670
+ @context.eval('result.values[0].id == 1').must_equal true
671
+ @context.eval('result.values[1].id == 3').must_equal true
672
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter2']).specificContext.rows[0]")
673
+ @context.eval('result.allValuesAny([2])').must_equal true
674
+ @context.eval('result.values[0].id == 1').must_equal true
675
+ @context.eval('result.values[1].id == 3').must_equal true
676
+
677
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop4,['OccurrenceAEncounter1']).specificContext.rows[0]")
678
+ @context.eval('result.values[0].id == 1').must_equal true
679
+ @context.eval('result.allValuesAny([1,2])').must_equal true
680
+
681
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop4,pop1,['OccurrenceAEncounter1']).specificContext.rows[0]")
682
+ @context.eval('result.values[0].id == 1').must_equal true
683
+ @context.eval('result.allValuesAny([1,2])').must_equal true
684
+
685
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop3,['OccurrenceAEncounter1','OccurrenceAEncounter2']).specificContext.rows[0]")
686
+ @context.eval('result.allValuesAny([1,2])').must_equal true
687
+ @context.eval('result.values[0].id == 1').must_equal true
688
+
689
+ end
602
690
 
603
691
  def test_intersect_all
604
692
 
@@ -774,20 +862,20 @@ class SpecificsTest < Test::Unit::TestCase
774
862
  "
775
863
  @context.eval(rows)
776
864
  @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows).length').must_equal 6
777
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[0].id').must_equal 10
778
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[1].id').must_equal 11
779
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[2].id').must_equal 12
780
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[3].id').must_equal 13
781
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[4].id').must_equal 14
782
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[5].id').must_equal 15
865
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[0].id').must_equal '10'
866
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[1].id').must_equal '11'
867
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[2].id').must_equal '12'
868
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[3].id').must_equal '13'
869
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[4].id').must_equal '14'
870
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[5].id').must_equal '15'
783
871
 
784
872
  @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows).length").must_equal 6
785
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[0].id").must_equal 10
786
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[1].id").must_equal 11
787
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[2].id").must_equal 12
788
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[3].id").must_equal 13
789
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[4].id").must_equal 14
790
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[5].id").must_equal 15
873
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[0].id").must_equal '10'
874
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[1].id").must_equal '11'
875
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[2].id").must_equal '12'
876
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[3].id").must_equal '13'
877
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[4].id").must_equal '14'
878
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[5].id").must_equal '15'
791
879
 
792
880
  end
793
881
 
@@ -830,30 +918,30 @@ class SpecificsTest < Test::Unit::TestCase
830
918
  exactly1 = 'new IVL_PQ(new PQ(1), new PQ(1))'
831
919
 
832
920
  @context.eval("specific1.COUNT(#{moreThanOne}).rows.length").must_equal 5
833
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[0].tempValue.id").must_equal 10
834
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[1].tempValue.id").must_equal 11
835
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[2].tempValue.id").must_equal 12
836
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[3].tempValue.id").must_equal 13
837
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[4].tempValue.id").must_equal 14
921
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[0].tempValue.id").must_equal '10'
922
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[1].tempValue.id").must_equal '11'
923
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[2].tempValue.id").must_equal '12'
924
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[3].tempValue.id").must_equal '13'
925
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[4].tempValue.id").must_equal '14'
838
926
  @context.eval("specific1.COUNT(#{lessThanThree}).rows.length").must_equal 3
839
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[0].tempValue.id").must_equal 10
840
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[1].tempValue.id").must_equal 11
841
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[2].tempValue.id").must_equal 15
927
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[0].tempValue.id").must_equal '10'
928
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[1].tempValue.id").must_equal '11'
929
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[2].tempValue.id").must_equal '15'
842
930
  @context.eval("specific1.COUNT(#{exactly1}).rows.length").must_equal 1
843
- @context.eval("specific1.COUNT(#{exactly1}).rows[0].tempValue.id").must_equal 15
931
+ @context.eval("specific1.COUNT(#{exactly1}).rows[0].tempValue.id").must_equal '15'
844
932
 
845
933
  @context.eval("specific2.COUNT(#{moreThanOne}).rows.length").must_equal 5
846
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[0].values[0].id").must_equal 10
847
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[1].values[0].id").must_equal 11
848
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[2].values[0].id").must_equal 12
849
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[3].values[0].id").must_equal 13
850
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[4].values[0].id").must_equal 14
934
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[0].values[0].id").must_equal '10'
935
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[1].values[0].id").must_equal '11'
936
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[2].values[0].id").must_equal '12'
937
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[3].values[0].id").must_equal '13'
938
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[4].values[0].id").must_equal '14'
851
939
  @context.eval("specific2.COUNT(#{lessThanThree}).rows.length").must_equal 3
852
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[0].values[0].id").must_equal 10
853
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[1].values[0].id").must_equal 11
854
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[2].values[0].id").must_equal 15
940
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[0].values[0].id").must_equal '10'
941
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[1].values[0].id").must_equal '11'
942
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[2].values[0].id").must_equal '15'
855
943
  @context.eval("specific2.COUNT(#{exactly1}).rows.length").must_equal 1
856
- @context.eval("specific2.COUNT(#{exactly1}).rows[0].values[0].id").must_equal 15
944
+ @context.eval("specific2.COUNT(#{exactly1}).rows[0].values[0].id").must_equal '15'
857
945
 
858
946
  @context.eval("specific3.COUNT(#{exactly1}).rows.length").must_equal 1
859
947
  @context.eval("specific4.COUNT(#{moreThanOne}).rows.length").must_equal 0
@@ -863,14 +951,14 @@ class SpecificsTest < Test::Unit::TestCase
863
951
  ##### FIRST
864
952
  ###
865
953
  @context.eval("specific1.FIRST().rows.length").must_equal 3
866
- @context.eval("specific1.FIRST().rows[0].tempValue.id").must_equal 11
867
- @context.eval("specific1.FIRST().rows[1].tempValue.id").must_equal 12
868
- @context.eval("specific1.FIRST().rows[2].tempValue.id").must_equal 15
954
+ @context.eval("specific1.FIRST().rows[0].tempValue.id").must_equal '11'
955
+ @context.eval("specific1.FIRST().rows[1].tempValue.id").must_equal '12'
956
+ @context.eval("specific1.FIRST().rows[2].tempValue.id").must_equal '15'
869
957
 
870
958
  @context.eval("specific2.FIRST().rows.length").must_equal 3
871
- @context.eval("specific2.FIRST().rows[0].values[0].id").must_equal 11
872
- @context.eval("specific2.FIRST().rows[1].values[0].id").must_equal 12
873
- @context.eval("specific2.FIRST().rows[2].values[0].id").must_equal 15
959
+ @context.eval("specific2.FIRST().rows[0].values[0].id").must_equal '11'
960
+ @context.eval("specific2.FIRST().rows[1].values[0].id").must_equal '12'
961
+ @context.eval("specific2.FIRST().rows[2].values[0].id").must_equal '15'
874
962
 
875
963
  @context.eval("specific3.FIRST().rows.length").must_equal 1
876
964
  @context.eval("specific4.FIRST().rows.length").must_equal 0
@@ -880,14 +968,14 @@ class SpecificsTest < Test::Unit::TestCase
880
968
  ###
881
969
 
882
970
  @context.eval("specific1.RECENT().rows.length").must_equal 3
883
- @context.eval("specific1.RECENT().rows[0].tempValue.id").must_equal 10
884
- @context.eval("specific1.RECENT().rows[1].tempValue.id").must_equal 13
885
- @context.eval("specific1.RECENT().rows[2].tempValue.id").must_equal 15
971
+ @context.eval("specific1.RECENT().rows[0].tempValue.id").must_equal '10'
972
+ @context.eval("specific1.RECENT().rows[1].tempValue.id").must_equal '13'
973
+ @context.eval("specific1.RECENT().rows[2].tempValue.id").must_equal '15'
886
974
 
887
975
  @context.eval("specific2.RECENT().rows.length").must_equal 3
888
- @context.eval("specific2.RECENT().rows[0].values[0].id").must_equal 10
889
- @context.eval("specific2.RECENT().rows[1].values[0].id").must_equal 13
890
- @context.eval("specific2.RECENT().rows[2].values[0].id").must_equal 15
976
+ @context.eval("specific2.RECENT().rows[0].values[0].id").must_equal '10'
977
+ @context.eval("specific2.RECENT().rows[1].values[0].id").must_equal '13'
978
+ @context.eval("specific2.RECENT().rows[2].values[0].id").must_equal '15'
891
979
 
892
980
  @context.eval("specific3.RECENT().rows.length").must_equal 1
893
981
  @context.eval("specific4.RECENT().rows.length").must_equal 0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hqmf2js
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-02-27 00:00:00.000000000 Z
14
+ date: 2013-04-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: nokogiri
@@ -100,7 +100,7 @@ dependencies:
100
100
  requirements:
101
101
  - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: 3.0.1
103
+ version: 3.1.1
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,7 +108,7 @@ dependencies:
108
108
  requirements:
109
109
  - - ~>
110
110
  - !ruby/object:Gem::Version
111
- version: 3.0.1
111
+ version: 3.1.1
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: hquery-patient-api
114
114
  requirement: !ruby/object:Gem::Requirement
@@ -116,7 +116,7 @@ dependencies:
116
116
  requirements:
117
117
  - - ~>
118
118
  - !ruby/object:Gem::Version
119
- version: 1.0.1
119
+ version: 1.0.2
120
120
  type: :runtime
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
@@ -124,7 +124,7 @@ dependencies:
124
124
  requirements:
125
125
  - - ~>
126
126
  - !ruby/object:Gem::Version
127
- version: 1.0.1
127
+ version: 1.0.2
128
128
  description: A library for converting HQMF files to executable JavaScript suitable
129
129
  for use with the hQuery Gateway
130
130
  email: hquery-talk@googlegroups.com
@@ -139,6 +139,7 @@ files:
139
139
  - README.md
140
140
  - Rakefile
141
141
  - VERSION
142
+ - app/assets/javascripts/crosswalk.js.coffee
142
143
  - app/assets/javascripts/custom_calculations.js.coffee
143
144
  - app/assets/javascripts/hqmf_util.js.coffee
144
145
  - app/assets/javascripts/logging_utils.js.coffee