-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcache.ts
More file actions
130 lines (113 loc) · 3.7 KB
/
cache.ts
File metadata and controls
130 lines (113 loc) · 3.7 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
128
129
130
import type { ResolvedValue } from './types.js'
export type CellListener = () => void
export interface DataFrameCache {
getCell(row: number, column: string): ResolvedValue | undefined
getRowNumber(row: number): ResolvedValue<number> | undefined
setCell(row: number, column: string, value: any): void
setRowNumber(row: number, rowNumber: number): void
registerCellListener(callback: CellListener): () => void
clearCache(): void
getCachedColumns(): string[]
getCachedRowsForColumn(column: string): number[]
}
/**
* Creates a cache for DataFrame cell data that automatically notifies listeners
* when cells are modified.
*/
export function createDataFrameCache(): DataFrameCache {
const cellCache = new Map<string, Map<number, ResolvedValue>>()
const rowNumberCache = new Map<number, ResolvedValue<number>>()
const listeners = new Set<CellListener>()
function notifyListeners(): void {
// Call all registered listeners
listeners.forEach(listener => {
try {
listener()
} catch (error) {
console.error('Error in DataFrameCache listener:', error)
}
})
}
return {
/**
* Get a cell value from the cache.
* Returns undefined if the cell hasn't been cached yet.
*/
getCell(row: number, column: string): ResolvedValue | undefined {
return cellCache.get(column)?.get(row)
},
/**
* Get a row number from the cache.
* Returns undefined if the row number hasn't been cached yet.
*/
getRowNumber(row: number): ResolvedValue<number> | undefined {
return rowNumberCache.get(row)
},
/**
* Set a cell value in the cache and trigger event listeners.
*/
setCell(row: number, column: string, value: any): void {
if (!cellCache.has(column)) {
cellCache.set(column, new Map())
}
const columnCache = cellCache.get(column)
if (!columnCache) {
throw new Error(`Column "${column}" not found in cache`)
}
const existingCell = columnCache.get(row)
const resolvedValue: ResolvedValue = { value }
// Only update and notify if the value has actually changed
if (!existingCell || existingCell.value !== value) {
columnCache.set(row, resolvedValue)
notifyListeners()
}
},
/**
* Set a row number in the cache and trigger event listeners.
*/
setRowNumber(row: number, rowNumber: number): void {
const existingRowNumber = rowNumberCache.get(row)
const resolvedValue: ResolvedValue<number> = { value: rowNumber }
// Only update and notify if the value has actually changed
if (!existingRowNumber || existingRowNumber.value !== rowNumber) {
rowNumberCache.set(row, resolvedValue)
notifyListeners()
}
},
/**
* Register a listener to be called when cells are updated.
* Returns a function to unregister the listener.
*/
registerCellListener(callback: CellListener): () => void {
listeners.add(callback)
return () => {
listeners.delete(callback)
}
},
/**
* Clear all cached data.
*/
clearCache(): void {
const hadData = cellCache.size > 0 || rowNumberCache.size > 0
cellCache.clear()
rowNumberCache.clear()
// Notify listeners if we had data before clearing
if (hadData) {
notifyListeners()
}
},
/**
* Get all cached columns.
*/
getCachedColumns(): string[] {
return Array.from(cellCache.keys())
},
/**
* Get all cached rows for a specific column.
*/
getCachedRowsForColumn(column: string): number[] {
const columnCache = cellCache.get(column)
return columnCache ? Array.from(columnCache.keys()) : []
},
}
}