app/assets/javascripts/hqmf_util.js.coffee in hqmf2js-1.2.1 vs app/assets/javascripts/hqmf_util.js.coffee in hqmf2js-1.3.0
- old
+ new
@@ -50,10 +50,11 @@
earlier = ts.asDate()
later = @date
else
earlier = @date
later = ts.asDate()
+ return Number.MAX_VALUE if !earlier? || !later?
if granularity=="a"
TS.yearsDifference(earlier,later)
else if granularity=="mo"
TS.monthsDifference(earlier,later)
else if granularity=="wk"
@@ -89,10 +90,13 @@
@afterOrConcurrent(other)
else
[a,b] = TS.dropSeconds(@date, other.date)
a.getTime() > b.getTime()
+ equals: (other) ->
+ (@date==null && other.date==null) || (@date.getTime()==other.date.getTime())
+
# Returns whether this TS is before or concurrent with the supplied TS ignoring seconds
beforeOrConcurrent: (other) ->
if @date==null || other.date==null
return false
[a,b] = TS.dropSeconds(@date, other.date)
@@ -396,43 +400,98 @@
SCWE: (other) ->
if @low && other.high
@low.asDate() && other.high.asDate() && @low.withinSameMinute(other.high)
else
false
+
+ equals: (other) ->
+ (@low==null && other.low==null) || (@low.equals(other.low)) && (@high==null && other.high==null) || (@high.equals(other.high))
+
@IVL_TS = IVL_TS
# Used to represent a value that will match any other value that is not null.
class ANYNonNull
constructor: ->
match: (scalarOrHash) ->
val = fieldOrContainerValue(scalarOrHash, 'scalar')
val != null
@ANYNonNull = ANYNonNull
+invokeOne = (patient, initialSpecificContext, fn) ->
+ if typeof(fn.isTrue)=='function' || typeof(fn)=='boolean'
+ fn
+ else
+ fn(patient, initialSpecificContext)
+@invokeOne = invokeOne
+
+evalUnlessShortCircuit = (fn) ->
+ # if we are short circuiting then return the function uncalled, if we are not then call the function and
+ # evaluate the tree. If uncalled, from here the function will only be called if required
+ if (Logger.short_circuit) then fn else fn()
+@evalUnlessShortCircuit = evalUnlessShortCircuit
+
+invokeAll = (patient, initialSpecificContext, fns) ->
+ (invokeOne(patient, initialSpecificContext, fn) for fn in fns)
+@invokeAll = invokeAll
+
# Returns true if one or more of the supplied values is true
-atLeastOneTrue = (precondition, values...) ->
- trueValues = (value for value in values when value && value.isTrue())
- trueValues.length>0
- hqmf.SpecificsManager.unionAll(new Boolean(trueValues.length>0), values)
+atLeastOneTrue = (precondition, patient, initialSpecificContext, valueFns...) ->
+ evalUnlessShortCircuit ->
+ values = invokeAll(patient, initialSpecificContext, valueFns)
+ trueValues = (value for value in values when value && value.isTrue())
+ hqmf.SpecificsManager.unionAll(new Boolean(trueValues.length>0), values)
@atLeastOneTrue = atLeastOneTrue
-
+
# Returns true if all of the supplied values are true
-allTrue = (precondition, values...) ->
- trueValues = (value for value in values when value && value.isTrue())
- hqmf.SpecificsManager.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
+allTrue = (precondition, patient, initialSpecificContext, valueFns...) ->
+ evalUnlessShortCircuit ->
+ values = []
+ for valueFn in valueFns
+ value = invokeOne(patient, initialSpecificContext, valueFn)
+ # break if the we have a false value and we're short circuiting.
+ #If we're not short circuiting then we want to calculate everything
+ break if value.isFalse() && Logger.short_circuit
+ values.push(value)
+ trueValues = (value for value in values when value && value.isTrue())
+ if trueValues.length==valueFns.length
+ hqmf.SpecificsManager.intersectAll(new Boolean(trueValues.length>0), trueValues)
+ else
+ # only intersect on false if we are not short circuiting.
+ # if we are not short circuiting then we want to have the specifics context returned for rationale
+ if Logger.short_circuit
+ value = new Boolean(false)
+ value.specificContext = hqmf.SpecificsManager.empty()
+ value
+ else
+ hqmf.SpecificsManager.intersectAll(new Boolean(false), values)
+
+
@allTrue = allTrue
# Returns true if one or more of the supplied values is false
-atLeastOneFalse = (precondition, values...) ->
- falseValues = (value for value in values when value.isFalse())
- hqmf.SpecificsManager.intersectAll(new Boolean(falseValues.length>0), values, true)
+atLeastOneFalse = (precondition, patient, initialSpecificContext, valueFns...) ->
+# values = invokeAll(patient, initialSpecificContext, valueFns)
+# falseValues = (value for value in values when value.isFalse())
+# hqmf.SpecificsManager.intersectAll(new Boolean(falseValues.length>0), values, true)
+ evalUnlessShortCircuit ->
+ values = []
+ hasFalse = false
+ for valueFn in valueFns
+ value = invokeOne(patient, initialSpecificContext, valueFn)
+ values.push(value)
+ if value.isFalse()
+ hasFalse = true
+ break if Logger.short_circuit
+ hqmf.SpecificsManager.intersectAll(new Boolean(values.length>0 && hasFalse), values, true)
@atLeastOneFalse = atLeastOneFalse
# Returns true if all of the supplied values are false
-allFalse = (precondition, values...) ->
- falseValues = (value for value in values when value.isFalse())
- hqmf.SpecificsManager.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
+allFalse = (precondition, patient, initialSpecificContext, valueFns...) ->
+ evalUnlessShortCircuit ->
+ values = invokeAll(patient, initialSpecificContext, valueFns)
+ falseValues = (value for value in values when value.isFalse())
+ hqmf.SpecificsManager.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
@allFalse = allFalse
# Return true if compareTo matches value
matchingValue = (value, compareTo) ->
new Boolean(compareTo.match(value))
@@ -445,11 +504,11 @@
@anyMatchingValue = anyMatchingValue
# Return only those events whose value matches the supplied value
filterEventsByValue = (events, value) ->
matchingEvents = (event for event in events when (anyMatchingValue(event, value)))
- matchingEvents
+ hqmf.SpecificsManager.maintainSpecifics(matchingEvents, events)
@filterEventsByValue = filterEventsByValue
# Return only those events with a field that matches the supplied value
filterEventsByField = (events, field, value) ->
respondingEvents = (event for event in events when event.respondTo(field))
@@ -528,15 +587,18 @@
@XPRODUCT = XPRODUCT
# Create a new list containing all the events from the supplied event lists
UNION = (eventLists...) ->
union = []
- # keep track of the specific occurrences by encounter ID. This is used in eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
+ # keep track of the specific occurrences by encounter ID. This is used in
+ # eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
specific_occurrence = {}
for eventList in eventLists
for event in eventList
- specific_occurrence[event.id] = eventList.specific_occurrence if eventList.specific_occurrence
+ if eventList.specific_occurrence
+ specific_occurrence[event.id] ||= []
+ specific_occurrence[event.id].push eventList.specific_occurrence
union.push(event)
union.specific_occurrence = specific_occurrence unless _.isEmpty(specific_occurrence)
hqmf.SpecificsManager.unionAll(union, eventLists)
@UNION = UNION
@@ -743,42 +805,55 @@
result.specificContext = result.specificContext[operator](range)
else
result.specificContext = result.specificContext[operator]()
result
+uniqueEvents = (events) ->
+ hash = {}
+ (hash[event.id] = event for event in events)
+ _.values(hash)
+@uniqueEvents = uniqueEvents
+
+# if we have multiple events at the same exact time and they happen to be the one selected by FIRST, RECENT, etc
+# then we want to select all of these issues as the first, most recent, etc.
+selectConcurrent = (target, events) ->
+ targetIVL = target.asIVL_TS()
+ uniqueEvents((result for result in events when result.asIVL_TS().equals(targetIVL)))
+@selectConcurrent = selectConcurrent
+
FIRST = (events) ->
result = []
- result = [events.sort(dateSortAscending)[0]] if (events.length > 0)
+ result = selectConcurrent(events.sort(dateSortAscending)[0], events) if (events.length > 0)
applySpecificOccurrenceSubset('FIRST',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FIRST = FIRST
SECOND = (events) ->
result = []
- result = [events.sort(dateSortAscending)[1]] if (events.length > 1)
+ result = selectConcurrent(events.sort(dateSortAscending)[1], events) if (events.length > 1)
applySpecificOccurrenceSubset('SECOND',hqmf.SpecificsManager.maintainSpecifics(result, events))
@SECOND = SECOND
THIRD = (events) ->
result = []
- result = [events.sort(dateSortAscending)[2]] if (events.length > 2)
+ result = selectConcurrent(events.sort(dateSortAscending)[2], events) if (events.length > 2)
applySpecificOccurrenceSubset('THIRD',hqmf.SpecificsManager.maintainSpecifics(result, events))
@THIRD = THIRD
FOURTH = (events) ->
result = []
- result = [events.sort(dateSortAscending)[3]] if (events.length > 3)
+ result = selectConcurrent(events.sort(dateSortAscending)[3], events) if (events.length > 3)
applySpecificOccurrenceSubset('FOURTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FOURTH = FOURTH
FIFTH = (events) ->
result = []
- result = [events.sort(dateSortAscending)[4]] if (events.length > 4)
+ result = selectConcurrent(events.sort(dateSortAscending)[4], events) if (events.length > 4)
applySpecificOccurrenceSubset('FIFTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FIFTH = FIFTH
RECENT = (events) ->
result = []
- result = [events.sort(dateSortDescending)[0]] if (events.length > 0)
+ result = selectConcurrent(events.sort(dateSortDescending)[0], events) if (events.length > 0)
applySpecificOccurrenceSubset('RECENT',hqmf.SpecificsManager.maintainSpecifics(result, events))
@RECENT = RECENT
LAST = (events) ->
RECENT(events)