44 lines
1.0 KiB
TypeScript
44 lines
1.0 KiB
TypeScript
let lastTimestamp = 0;
|
|
let sameTimestampSequence = 0;
|
|
|
|
export interface DedupeEntityIdsResult<T> {
|
|
items: T[];
|
|
changed: boolean;
|
|
}
|
|
|
|
export function createEntityId(prefix: string, timestamp = Date.now()): string {
|
|
if (timestamp === lastTimestamp) {
|
|
sameTimestampSequence += 1;
|
|
} else {
|
|
lastTimestamp = timestamp;
|
|
sameTimestampSequence = 0;
|
|
}
|
|
return `${prefix}-${timestamp}-${sameTimestampSequence.toString(36)}`;
|
|
}
|
|
|
|
export function dedupeEntityIds<T extends { id: string }>(
|
|
items: T[],
|
|
prefix: string,
|
|
timestamp = Date.now(),
|
|
): DedupeEntityIdsResult<T> {
|
|
const seen = new Set<string>();
|
|
let changed = false;
|
|
|
|
const deduped = items.map((item) => {
|
|
if (item.id && !seen.has(item.id)) {
|
|
seen.add(item.id);
|
|
return item;
|
|
}
|
|
|
|
changed = true;
|
|
let nextId = createEntityId(prefix, timestamp);
|
|
while (seen.has(nextId)) {
|
|
nextId = createEntityId(prefix, timestamp);
|
|
}
|
|
seen.add(nextId);
|
|
return { ...item, id: nextId };
|
|
});
|
|
|
|
return { items: changed ? deduped : items, changed };
|
|
}
|