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 +1 -1
- data/Gemfile.lock +9 -42
- data/app/assets/javascripts/crosswalk.js.coffee +72 -0
- data/app/assets/javascripts/hqmf_util.js.coffee +12 -3
- data/app/assets/javascripts/logging_utils.js.coffee +71 -24
- data/app/assets/javascripts/patient_api_extension.js.coffee +4 -0
- data/app/assets/javascripts/specifics.js.coffee +44 -16
- data/hqmf2js.gemspec +3 -3
- data/lib/generator/characteristic.js.erb +1 -1
- data/lib/generator/codes_to_json.rb +0 -4
- data/lib/generator/js.rb +23 -15
- data/test/unit/codes_to_json_test.rb +0 -14
- data/test/unit/library_function_test.rb +8 -0
- data/test/unit/specifics_test.rb +135 -47
- metadata +7 -6
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hqmf2js (1.2.
|
4
|
+
hqmf2js (1.2.1)
|
5
5
|
coffee-script (~> 2.2.0)
|
6
|
-
health-data-standards (~> 3.
|
7
|
-
hquery-patient-api (~> 1.0.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
@
|
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
|
-
@
|
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(
|
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
|
-
|
74
|
+
# Wrap all of the data criteria functions generated from HQMF
|
46
75
|
_.each(_.functions(hqmfjs), (method) ->
|
47
|
-
|
76
|
+
if method != 'initializeSpecifics'
|
77
|
+
hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
|
48
78
|
|
49
|
-
|
79
|
+
args = Array.prototype.slice.call(arguments,1)
|
50
80
|
|
51
|
-
|
52
|
-
|
53
|
-
|
81
|
+
Logger.info("#{method}:")
|
82
|
+
Logger.indentCount++
|
83
|
+
result = func.apply(this, args)
|
54
84
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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: (
|
77
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
18
|
-
s.add_dependency 'hquery-patient-api', '~> 1.0.
|
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 -%>
|
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
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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")'
|
data/test/unit/specifics_test.rb
CHANGED
@@ -19,7 +19,7 @@ class SpecificsTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
|
22
|
-
def
|
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.
|
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-
|
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.
|
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.
|
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.
|
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.
|
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
|