68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { type OperationInterval,
|
|
operationIntervalsOverlap,
|
|
operationsSyncPriority } from './operations-sync-plan';
|
|
|
|
export type OperationsIntent = {
|
|
atomic: boolean;
|
|
atomicIntervals?: string[];
|
|
intervals: string[];
|
|
screenIntervals?: string[];
|
|
};
|
|
|
|
export function intervalKey(interval: OperationInterval): string {
|
|
// eslint-disable-next-line sonarjs/no-inverted-boolean-check -- Negation also rejects Invalid Date; >= would silently accept NaN.
|
|
if (!(interval.from < interval.to)) {
|
|
throw new Error('Invalid operations interval');
|
|
}
|
|
return JSON.stringify([
|
|
interval.accountId,
|
|
interval.from.toISOString(),
|
|
interval.to.toISOString(),
|
|
interval.instrumentUid ?? '',
|
|
]);
|
|
}
|
|
|
|
export function decodeInterval(key: string): OperationInterval {
|
|
const [accountId, from, to, instrumentUid] = JSON.parse(key) as string[];
|
|
return {
|
|
accountId,
|
|
from: new Date(from),
|
|
to: new Date(to),
|
|
...(instrumentUid ? { instrumentUid } : {}),
|
|
};
|
|
}
|
|
|
|
export function extendRunningIntent(input: {
|
|
additions: OperationInterval[];
|
|
intervals: OperationInterval[];
|
|
pending: OperationInterval[];
|
|
previous: OperationsIntent | undefined;
|
|
previousPriority: number;
|
|
priority: number;
|
|
publicationAtomic: boolean;
|
|
}): OperationsIntent {
|
|
const { previous, pending, additions, intervals, priority, previousPriority, publicationAtomic } = input;
|
|
const overlapsRequested = (item: OperationInterval) =>
|
|
intervals.some((target) => operationIntervalsOverlap(item, target));
|
|
const retainedScreen = previous?.screenIntervals ??
|
|
(previousPriority === operationsSyncPriority.screen ? (previous?.intervals ?? []) : []);
|
|
const addedScreen = priority === operationsSyncPriority.screen
|
|
? [...pending, ...additions].filter(overlapsRequested).map(intervalKey)
|
|
: [];
|
|
const ordered = priority < previousPriority
|
|
? [
|
|
...pending.filter(overlapsRequested),
|
|
...additions,
|
|
...pending.filter((item) => !overlapsRequested(item)),
|
|
]
|
|
: [...pending, ...additions];
|
|
return {
|
|
atomic: previous?.atomic ?? publicationAtomic,
|
|
atomicIntervals: previous?.atomic
|
|
? [...new Set([...(previous.atomicIntervals ?? previous.intervals), ...additions.map(intervalKey)])]
|
|
: [],
|
|
screenIntervals: [...new Set([...retainedScreen, ...addedScreen])],
|
|
intervals: ordered.map(intervalKey),
|
|
};
|
|
}
|