All files / layers / L1 mutationQueue.ts

68.18% Statements 30/44
70% Branches 14/20
75% Functions 15/20
66.66% Lines 24/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 7256x                   1756x           52x     29x 29x 29x       4x       52x       3x         16732x 20284x 5044x               2x 2x 2x 3x     2x       3x 3x 3x           172x 67x   172x 172x  
/**
 * @see frontend/docs/UX/layer-contracts/L1-data-layer.md §5.1
 *   (Poiston lykätty evikointi — pendingDeleteMap)
 * @see frontend/docs/UX/layer-contracts/L1-data-layer.md §9.4
 *   (Mutaationjono — offline-jonotus ja replay)
 *
 * Sync in-memory Map (pendingDeleteMap) + IndexedDB-persistointi
 * poiston lykättyyn evikointiin. Render-path lukee synkronisesti
 * ilman asynkroniaa. Mutaationjono persistoi offline-poistot
 * IndexedDB:hen ja purkaa ne yhteyden palautuessa.
 *
 * Liittyy periaatteisiin: 8, 9
 */

import type { QueryParams } from '../interfaces'
 
export const pendingDeleteMap = new Map<string, Set<string>>()

export function addPendingDelete(entityPath: string, id: string): void {
  const set = pendingDeleteMap.get(entityPath) ?? new Set()
  set.add(id)
  pendingDeleteMap.set(entityPath, set)
}

export function removePendingDelete(entityPath: string, id: string): void {
  pendingDeleteMap.get(entityPath)?.delete(id)
}
 
export function getPendingDeletes(entityPath: string): Set<string> {
  return pendingDeleteMap.get(entityPath) ?? new Set()
}
 
export function isMarkedDeleted(entityPath: string, id: string): boolean {
  return pendingDeleteMap.get(entityPath)?.has(id) ?? false
}

export function populatePendingDeletes(
  entries: Array<{ entityPath: string; id: string }>,
): void {
  for (const { entityPath, id } of entries) {
    addPendingDelete(entityPath, id)
  }
}
 
export function getAllPendingDeleteEntries(): Array<{
  entityPath: string
  id: string
}> {
  const entries: Array<{ entityPath: string; id: string }> = []
  for (const [entityPath, ids] of pendingDeleteMap) {
    for (const id of ids) {
      entries.push({ entityPath, id })
    }
  }
  return entries
}
 
export function purgePendingDeletes(entityPath: string): Set<string> {
  const set = pendingDeleteMap.get(entityPath) ?? new Set()
  pendingDeleteMap.delete(entityPath)
  return set
}
 
export function normalizeFilters<T extends QueryParams>(
  filters: T,
): Partial<Record<string, string | number | boolean>> {
  const entries = Object.entries(filters).filter(
    ([, v]) => v !== undefined && v !== '',
  )
  entries.sort(([a], [b]) => a.localeCompare(b))
  return Object.fromEntries(entries)
}