app/assets/javascripts/hqmf_util.js.coffee in hqmf2js-1.0.1 vs app/assets/javascripts/hqmf_util.js.coffee in hqmf2js-1.1.0
- old
+ new
@@ -13,30 +13,30 @@
if isNaN(hour)
hour = 0
minute = parseInt(hl7ts.substring(10,12), 10)
if isNaN(minute)
minute = 0
- @date = new Date(year, month, day, hour, minute)
+ @date = new Date(Date.UTC(year, month, day, hour, minute))
else
@date = new Date()
# Add a time period to th and return it
# pq - a time period as an instance of PQ. Supports units of a (year), mo (month),
# wk (week), d (day), h (hour) and min (minute).
add: (pq) ->
if pq.unit=="a"
- @date.setFullYear(@date.getFullYear()+pq.value)
+ @date.setUTCFullYear(@date.getUTCFullYear()+pq.value)
else if pq.unit=="mo"
- @date.setMonth(@date.getMonth()+pq.value)
+ @date.setUTCMonth(@date.getUTCMonth()+pq.value)
else if pq.unit=="wk"
- @date.setDate(@date.getDate()+(7*pq.value))
+ @date.setUTCDate(@date.getUTCDate()+(7*pq.value))
else if pq.unit=="d"
- @date.setDate(@date.getDate()+pq.value)
+ @date.setUTCDate(@date.getUTCDate()+pq.value)
else if pq.unit=="h"
- @date.setHours(@date.getHours()+pq.value)
+ @date.setUTCHours(@date.getUTCHours()+pq.value)
else if pq.unit=="min"
- @date.setMinutes(@date.getMinutes()+pq.value)
+ @date.setUTCMinutes(@date.getUTCMinutes()+pq.value)
else
throw "Unknown time unit: "+pq.unit
this
# Returns the difference between this TS and the supplied TS as an absolute
@@ -74,21 +74,21 @@
# Returns whether this TS is before the supplied TS ignoring seconds
before: (other) ->
if @date==null || other.date==null
return false
if other.inclusive
- beforeOrConcurrent(other)
+ @beforeOrConcurrent(other)
else
[a,b] = TS.dropSeconds(@date, other.date)
a.getTime() < b.getTime()
# Returns whether this TS is after the supplied TS ignoring seconds
after: (other) ->
if @date==null || other.date==null
return false
if other.inclusive
- afterOrConcurrent(other)
+ @afterOrConcurrent(other)
else
[a,b] = TS.dropSeconds(@date, other.date)
a.getTime() > b.getTime()
# Returns whether this TS is before or concurrent with the supplied TS ignoring seconds
@@ -111,25 +111,25 @@
[a,b] = TS.dropSeconds(@date, other.date)
a.getTime()==b.getTime()
# Number of whole years between the two time stamps (as Date objects)
@yearsDifference: (earlier, later) ->
- if (later.getMonth() < earlier.getMonth())
- later.getFullYear()-earlier.getFullYear()-1
- else if (later.getMonth() == earlier.getMonth() && later.getDate() >= earlier.getDate())
- later.getFullYear()-earlier.getFullYear()
- else if (later.getMonth() == earlier.getMonth() && later.getDate() < earlier.getDate())
- later.getFullYear()-earlier.getFullYear()-1
+ if (later.getUTCMonth() < earlier.getUTCMonth())
+ later.getUTCFullYear()-earlier.getUTCFullYear()-1
+ else if (later.getUTCMonth() == earlier.getUTCMonth() && later.getUTCDate() >= earlier.getUTCDate())
+ later.getUTCFullYear()-earlier.getUTCFullYear()
+ else if (later.getUTCMonth() == earlier.getUTCMonth() && later.getUTCDate() < earlier.getUTCDate())
+ later.getUTCFullYear()-earlier.getUTCFullYear()-1
else
- later.getFullYear()-earlier.getFullYear()
+ later.getUTCFullYear()-earlier.getUTCFullYear()
# Number of whole months between the two time stamps (as Date objects)
@monthsDifference: (earlier, later) ->
- if (later.getDate() >= earlier.getDate())
- (later.getFullYear()-earlier.getFullYear())*12+later.getMonth()-earlier.getMonth()
+ if (later.getUTCDate() >= earlier.getUTCDate())
+ (later.getUTCFullYear()-earlier.getUTCFullYear())*12+later.getUTCMonth()-earlier.getUTCMonth()
else
- (later.getFullYear()-earlier.getFullYear())*12+later.getMonth()-earlier.getMonth()-1
+ (later.getUTCFullYear()-earlier.getUTCFullYear())*12+later.getUTCMonth()-earlier.getUTCMonth()-1
# Number of whole minutes between the two time stamps (as Date objects)
@minutesDifference: (earlier, later) ->
Math.floor(((later.getTime()-earlier.getTime())/1000)/60)
@@ -138,14 +138,12 @@
Math.floor(TS.minutesDifference(earlier,later)/60)
# Number of days betweem the two time stamps (as Date objects)
@daysDifference: (earlier, later) ->
# have to discard time portion for day difference calculation purposes
- e = new Date(earlier.getFullYear(), earlier.getMonth(), earlier.getDate())
- e.setUTCHours(0)
- l = new Date(later.getFullYear(), later.getMonth(), later.getDate())
- l.setUTCHours(0)
+ e = new Date(Date.UTC(earlier.getUTCFullYear(), earlier.getUTCMonth(), earlier.getUTCDate()))
+ l = new Date(Date.UTC(later.getUTCFullYear(), later.getUTCMonth(), later.getUTCDate()))
Math.floor(TS.hoursDifference(e,l)/24)
# Number of whole weeks between the two time stmaps (as Date objects)
@weeksDifference: (earlier, later) ->
Math.floor(TS.daysDifference(earlier,later)/7)
@@ -411,29 +409,29 @@
# Returns true if one or more of the supplied values is true
atLeastOneTrue = (values...) ->
trueValues = (value for value in values when value && value.isTrue())
trueValues.length>0
- Specifics.unionAll(new Boolean(trueValues.length>0), values)
+ hqmf.SpecificsManager.unionAll(new Boolean(trueValues.length>0), values)
@atLeastOneTrue = atLeastOneTrue
# Returns true if all of the supplied values are true
allTrue = (values...) ->
trueValues = (value for value in values when value && value.isTrue())
- Specifics.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
+ hqmf.SpecificsManager.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
@allTrue = allTrue
# Returns true if one or more of the supplied values is false
atLeastOneFalse = (values...) ->
falseValues = (value for value in values when value.isFalse())
- Specifics.intersectAll(new Boolean(falseValues.length>0), values, true)
+ hqmf.SpecificsManager.intersectAll(new Boolean(falseValues.length>0), values, true)
@atLeastOneFalse = atLeastOneFalse
# Returns true if all of the supplied values are false
allFalse = (values...) ->
falseValues = (value for value in values when value.isFalse())
- Specifics.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
+ 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))
@@ -452,16 +450,60 @@
@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))
- event for event in respondingEvents when value.match(event[field]())
+ result = (event for event in respondingEvents when value.match(event[field]()))
+ hqmf.SpecificsManager.maintainSpecifics(result, events)
@filterEventsByField = filterEventsByField
+shiftTimes = (event, field) ->
+ shiftedEvent = new event.constructor(event.json)
+ shiftedEvent.setTimestamp(shiftedEvent[field]())
+ shiftedEvent
+@shiftTimes = shiftTimes
+
+adjustBoundsForField = (events, field) ->
+ validEvents = (event for event in events when (event.respondTo(field) and event[field]()))
+ shiftedEvents = (shiftTimes(event, field) for event in validEvents)
+ hqmf.SpecificsManager.maintainSpecifics(shiftedEvents, events)
+@adjustBoundsForField = adjustBoundsForField
+
+# Clone the supplied event and replace any facilities with just the supplied one
+narrowEventForFacility = (event, facility) ->
+ narrowed = new event.constructor(event.json)
+ # uncomment the following line when patient API is modified to support multiple
+ # facilities
+ # narrowed._facilities = [facility]
+ narrowed
+@narrowEventForFacility = narrowEventForFacility
+
+# Return a cloned set of events, each with just one of the original facilities
+denormalizeEvent = (event) ->
+ # the following line should be changed when the patient API is modified to support
+ # more than one facility per encounter
+ # narrowed = (narrowEventForFacility(event, facility) for facility in event.facilities)
+ narrowed = (narrowEventForFacility(event, facility) for facility in [event.facility])
+@denormalizeEvent = denormalizeEvent
+
+# Creates a new set of events with one location per event. Input events with more than
+# one location will be duplicated once per location and each resulting event will
+# be assigned one location. Start and end times of the event will be adjusted to match the
+# value of the supplied field
+denormalizeEventsByLocation = (events, field) ->
+ respondingEvents = (event for event in events when event.respondTo("facility") and event.facility())
+ denormalizedEvents = (denormalizeEvent(event) for event in respondingEvents)
+ denormalizedEvents = [].concat denormalizedEvents...
+ result = adjustBoundsForField(denormalizedEvents, field)
+ hqmf.SpecificsManager.maintainSpecifics(result, events)
+@denormalizeEventsByLocation = denormalizeEventsByLocation
+
# Utility method to obtain the value set for an OID
getCodes = (oid) ->
- OidDictionary[oid]
+ codes = OidDictionary[oid]
+ throw "value set oid could not be found: #{oid}" unless codes?
+ codes
@getCodes = getCodes
# Used for representing XPRODUCTs of arrays, holds both a flattened array that contains
# all the elements of the compoent arrays and the component arrays themselves
class CrossProduct extends Array
@@ -473,27 +515,27 @@
for event in eventList
this.push(event)
# Create a CrossProduct of the supplied event lists.
XPRODUCT = (eventLists...) ->
- Specifics.intersectAll(new CrossProduct(eventLists), eventLists)
+ hqmf.SpecificsManager.intersectAll(new CrossProduct(eventLists), eventLists)
@XPRODUCT = XPRODUCT
# Create a new list containing all the events from the supplied event lists
UNION = (eventLists...) ->
union = []
for eventList in eventLists
for event in eventList
union.push(event)
- Specifics.unionAll(union, eventLists)
+ hqmf.SpecificsManager.unionAll(union, eventLists)
@UNION = UNION
# Return true if the number of events matches the supplied range
COUNT = (events, range) ->
count = events.length
result = new Boolean(range.match(count))
- applySpecificOccurrenceSubset('COUNT', Specifics.maintainSpecifics(result, events), range)
+ applySpecificOccurrenceSubset('COUNT', hqmf.SpecificsManager.maintainSpecifics(result, events), range)
@COUNT = COUNT
# Convert an hQuery.CodedEntry or JS Date into an IVL_TS
getIVL = (eventOrTimeStamp) ->
if eventOrTimeStamp.asIVL_TS
@@ -519,11 +561,12 @@
'EDU': 'high',
'ECW': 'high'
'SCW': 'low',
'ECWS': 'high'
'SCWE': 'low',
- 'CONCURRENT': 'low'
+ 'CONCURRENT': 'low',
+ 'DATEDIFF': 'low'
}
boundAccessor = {
'DURING': 'low',
'OVERLAP': 'low',
@@ -539,11 +582,12 @@
'EDU': 'low',
'ECW': 'high'
'SCW': 'low',
'ECWS': 'low'
'SCWE': 'high',
- 'CONCURRENT': 'low'
+ 'CONCURRENT': 'low',
+ 'DATEDIFF': 'low'
}
# Determine whether the supplied event falls within range of the supplied bound
# using the method to determine which property of the event and bound to use in
# the comparison. E.g. if method is SBS then check whether the start of the event
@@ -561,41 +605,41 @@
matchingBounds = []
for boundList in bounds.eventLists
currentMatches = eventMatchesBounds(event, boundList, methodName, range)
return [] if (currentMatches.length == 0)
matchingBounds = matchingBounds.concat(currentMatches)
- return Specifics.maintainSpecifics(matchingBounds,bounds)
+ return hqmf.SpecificsManager.maintainSpecifics(matchingBounds,bounds)
else
eventIVL = getIVL(event)
matchingBounds = (bound for bound in bounds when (
boundIVL = getIVL(bound)
result = eventIVL[methodName](boundIVL)
if result && range
result &&= withinRange(methodName, eventIVL, boundIVL, range)
result
))
- Specifics.maintainSpecifics(matchingBounds, bounds)
+ hqmf.SpecificsManager.maintainSpecifics(matchingBounds, bounds)
@eventMatchesBounds = eventMatchesBounds
# Determine which event match one of the supplied bounds
eventsMatchBounds = (events, bounds, methodName, range) ->
if (bounds.length==undefined)
bounds = [bounds]
if (events.length==undefined)
events = [events]
- specificContext = new Specifics()
+ specificContext = new hqmf.SpecificOccurrence()
hasSpecificOccurrence = (events.specific_occurrence? || bounds.specific_occurrence?)
matchingEvents = []
matchingEvents.specific_occurrence = events.specific_occurrence
for event in events
matchingBounds=eventMatchesBounds(event, bounds, methodName, range)
matchingEvents.push(event) if matchingBounds.length > 0
if hasSpecificOccurrence
matchingEvents.specific_occurrence = events.specific_occurrence
- # TODO: we'll need a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
+ # 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
specificContext.addRows(Row.buildRowsForMatching(events.specific_occurrence, event, bounds.specific_occurrence, matchingBounds))
else
# add all stars
specificContext.addIdentityRow()
@@ -691,41 +735,41 @@
result
FIRST = (events) ->
result = []
result = [events.sort(dateSortAscending)[0]] if (events.length > 0)
- applySpecificOccurrenceSubset('FIRST',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('FIRST',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FIRST = FIRST
SECOND = (events) ->
result = []
result = [events.sort(dateSortAscending)[1]] if (events.length > 1)
- applySpecificOccurrenceSubset('SECOND',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('SECOND',hqmf.SpecificsManager.maintainSpecifics(result, events))
@SECOND = SECOND
THIRD = (events) ->
result = []
result = [events.sort(dateSortAscending)[2]] if (events.length > 2)
- applySpecificOccurrenceSubset('THIRD',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('THIRD',hqmf.SpecificsManager.maintainSpecifics(result, events))
@THIRD = THIRD
FOURTH = (events) ->
result = []
result = [events.sort(dateSortAscending)[3]] if (events.length > 3)
- applySpecificOccurrenceSubset('FOURTH',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('FOURTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FOURTH = FOURTH
FIFTH = (events) ->
result = []
result = [events.sort(dateSortAscending)[4]] if (events.length > 4)
- applySpecificOccurrenceSubset('FIFTH',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('FIFTH',hqmf.SpecificsManager.maintainSpecifics(result, events))
@FIFTH = FIFTH
RECENT = (events) ->
result = []
result = [events.sort(dateSortDescending)[0]] if (events.length > 0)
- applySpecificOccurrenceSubset('RECENT',Specifics.maintainSpecifics(result, events))
+ applySpecificOccurrenceSubset('RECENT',hqmf.SpecificsManager.maintainSpecifics(result, events))
@RECENT = RECENT
LAST = (events) ->
RECENT(events)
@LAST = LAST
@@ -757,19 +801,26 @@
MIN = (events, range) ->
minValue = Infinity
if (events.length > 0)
minValue = events.sort(valueSortAscending)[0].value()["scalar"]
result = new Boolean(range.match(minValue))
- applySpecificOccurrenceSubset('MIN',Specifics.maintainSpecifics(result, events), range)
+ applySpecificOccurrenceSubset('MIN',hqmf.SpecificsManager.maintainSpecifics(result, events), range)
@MIN = MIN
MAX = (events, range) ->
maxValue = -Infinity
if (events.length > 0)
maxValue = events.sort(valueSortDescending)[0].value()["scalar"]
result = new Boolean(range.match(maxValue))
- applySpecificOccurrenceSubset('MAX',Specifics.maintainSpecifics(result, events), range)
+ applySpecificOccurrenceSubset('MAX',hqmf.SpecificsManager.maintainSpecifics(result, events), range)
@MAX = MAX
+
+DATEDIFF = (events, range) ->
+ return hqmf.SpecificsManager.maintainSpecifics(new Boolean(false), events) if events.length < 2
+ throw "cannot calculate against more than 2 events" if events.length > 2
+ hqmf.SpecificsManager.maintainSpecifics(new Boolean(withinRange('DATEDIFF', getIVL(events[0]), getIVL(events[1]), range)), events)
+@DATEDIFF = DATEDIFF
+
@OidDictionary = {};
hqmfjs = hqmfjs||{}
@hqmfjs = @hqmfjs||{};