-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmerge.ts
More file actions
115 lines (98 loc) · 3.67 KB
/
merge.ts
File metadata and controls
115 lines (98 loc) · 3.67 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
import mergeWith from 'lodash.mergewith';
import cloneDeep from 'lodash.clonedeep';
import { patch } from '@n1ru4l/json-patch-plus';
import { GroupedEventDBScheme, RepetitionDBScheme } from '@hawk.so/types';
/**
* One of the features of the events is that their repetition is the difference
* between the original, which greatly optimizes storage. So we need to restore
* the original repetition payload using the very first event and its difference
* between its repetition
*
* @param originalEvent - the very first event we received
* @param repetition - the difference with its repetition, for the repetition we want to display
* @returns fully assembled payload of the current repetition
*/
export function repetitionAssembler(originalEvent: Record<string, any>, repetition: { [key: string]: any }): any {
const customizer = (originalParam: any, repetitionParam: any): any => {
if (repetitionParam === null) {
return originalParam;
}
if (typeof repetitionParam === 'object' && typeof originalParam === 'object') {
/**
* If original event has null but repetition has some value, we need to return repetition value
*/
if (originalParam === null) {
return repetitionParam;
/**
* Otherwise, we need to recursively merge original and repetition values
*/
} else {
return repetitionAssembler(originalParam, repetitionParam);
}
}
return repetitionParam;
};
return mergeWith(cloneDeep(originalEvent), cloneDeep(repetition), customizer);
}
function parsePayloadField(payload: any, field: string) {
if (payload && payload[field] && typeof payload[field] === 'string') {
payload[field] = JSON.parse(payload[field]);
}
return payload;
}
function stringifyPayloadField(payload: any, field: string) {
if (payload && payload[field]) {
payload[field] = JSON.stringify(payload[field]);
}
return payload;
}
/**
* Helps to merge original event and repetition due to delta format,
* in case of old delta format, we need to patch the payload
* in case of new delta format, we need to assemble the payload
*
* @param originalEvent {HawkEvent} - The original event
* @param repetition {HawkEventRepetition} - The repetition to process
* @returns {HawkEvent} Updated event with processed repetition payload
*/
export function composeFullRepetitionEvent(originalEvent: GroupedEventDBScheme, repetition: RepetitionDBScheme | undefined): GroupedEventDBScheme {
/**
* Make a deep copy of the original event, because we need to avoid mutating the original event
*/
const event = cloneDeep(originalEvent);
if (!repetition) {
return event;
}
/**
* New delta format (repetition.delta is not null)
*/
if (repetition.delta) {
/**
* Parse addons and context fields from string to object before patching
*/
event.payload = parsePayloadField(event.payload, 'addons');
event.payload = parsePayloadField(event.payload, 'context');
event.payload = patch({
left: event.payload,
delta: JSON.parse(repetition.delta),
});
/**
* Stringify addons and context fields from object to string after patching
*/
event.payload = stringifyPayloadField(event.payload, 'addons');
event.payload = stringifyPayloadField(event.payload, 'context');
return event;
}
/**
* New delta format (repetition.payload is null) and repetition.delta is null (there is no delta between original and repetition)
*/
if (!repetition.payload) {
return event;
}
/**
* Old delta format (repetition.payload is not null)
* @todo remove after July 5 2025
*/
event.payload = repetitionAssembler(event.payload, repetition.payload);
return event;
}