-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgetStatusUpdates.ts
More file actions
127 lines (111 loc) · 4.76 KB
/
getStatusUpdates.ts
File metadata and controls
127 lines (111 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import {Logger} from "@aws-lambda-powertools/logger"
import {injectLambdaContext} from "@aws-lambda-powertools/logger/middleware"
import middy from "@middy/core"
import inputOutputLogger from "@middy/input-output-logger"
import validator from "@middy/validator"
import {transpileSchema} from "@middy/validator/transpile"
import {MiddyErrorHandler} from "@psu-common/middyErrorHandler"
import {getItemsUpdatesForPrescription} from "./dynamoDBclient.ts"
import {requestSchema, requestType, inputPrescriptionType} from "./schema/request.ts"
import {responseType, outputPrescriptionType, itemType} from "./schema/response.ts"
const logger = new Logger({serviceName: "GSUL"})
const errorResponseBody: responseType = {
schemaVersion: 1,
isSuccess: false,
prescriptions: []
}
const middyErrorHandler = new MiddyErrorHandler(errorResponseBody)
const lambdaHandler = async (event: requestType): Promise<responseType> => {
// there are deliberately no try..catch blocks in this as any errors are caught by custom middy error handler
// and an error response is sent
// this is an async map so it returns an array of promises
const itemResults = event.prescriptions.map(async (prescription) => {
const queryResult = await getItemsUpdatesForPrescription(prescription.prescriptionID, prescription.odsCode, logger)
return filterOutFutureReduceToLatestUpdates(prescription, queryResult)
})
// wait for all the promises to complete
const finalResults = await Promise.all(itemResults)
const response = {
schemaVersion: 1,
isSuccess: true,
prescriptions: finalResults
}
return response
}
export const filterOutFutureReduceToLatestUpdates = (
inputPrescription: inputPrescriptionType,
items: Array<itemType>,
currentTime: number = Date.now() // injectable for testing
): outputPrescriptionType => {
// filter out items with future lastUpdateDateTime
const validTimeUpdates = items.filter(item => {
const updateTime = Date.parse(item.lastUpdateDateTime)
return updateTime <= currentTime
})
// group by itemId and separate post-dated from regular updates
const itemGroups: Record<string, {regular: itemType | null, postDated: itemType | null}> = {}
validTimeUpdates.forEach(item => {
if (!itemGroups[item.itemId]) {
itemGroups[item.itemId] = {regular: null, postDated: null}
}
const group = itemGroups[item.itemId]
if (item.postDatedLastModifiedSetAt && !group.postDated) { // this is a post-dated update
group.postDated = item
} else if (item.postDatedLastModifiedSetAt && group.postDated) { // also a post-dated update
const existingTime = Date.parse(group.postDated.postDatedLastModifiedSetAt)
const newTime = Date.parse(item.postDatedLastModifiedSetAt)
if (newTime > existingTime) {
group.postDated = item
}
} else if (!group.regular) { // this is a regular update
group.regular = item
} else if (group.regular) { // also a regular update
const existingTime = Date.parse(group.regular.lastUpdateDateTime)
const newTime = Date.parse(item.lastUpdateDateTime)
if (newTime > existingTime) {
group.regular = item
}
}
})
// flatten both regular and post-dated updates into single array
// but exclude post-dated updates if they have been revoked by a subsequent regular update
const uniqueItems: Array<itemType> = []
Object.values(itemGroups).forEach(group => {
if (group.regular) uniqueItems.push(group.regular)
if (group.postDated) {
// Only include post-dated update if there's no regular update that came after it was set
const postDatedSetTime = Date.parse(group.postDated.postDatedLastModifiedSetAt)
const regularUpdateTime = group.regular ? Date.parse(group.regular.lastUpdateDateTime) : 0
// If the regular update came after the post-dated was set, it revokes the post-dated update
if (!group.regular || regularUpdateTime <= postDatedSetTime) {
uniqueItems.push(group.postDated)
}
}
})
const result: outputPrescriptionType = {
prescriptionID: inputPrescription.prescriptionID,
onboarded: items.length > 0, // consider onboarded even if all updates were post-dated
items: uniqueItems
}
return result
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger, {clearState: true}))
.use(
inputOutputLogger({
logger: (request) => {
const response = (request as {response?: unknown} | null | undefined)?.response
if (response === undefined) {
logger.info("inputOutputLogger request", {request})
} else {
logger.info("inputOutputLogger response", {response})
}
}
})
)
.use(middyErrorHandler.errorHandler({logger: logger}))
.use(
validator({
eventSchema: transpileSchema(requestSchema)
})
)